CallInfo.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. enum CallFlags : unsigned
  9. {
  10. CallFlags_None = 0,
  11. CallFlags_New = 1,
  12. CallFlags_Value = 2,
  13. CallFlags_Eval = 4,
  14. CallFlags_ExtraArg = 8,
  15. CallFlags_NotUsed = 0x10,
  16. CallFlags_Wrapped = 0x20,
  17. CallFlags_NewTarget = 0x40,
  18. CallFlags_InternalFrame = 0x80
  19. };
  20. ENUM_CLASS_HELPERS(CallFlags, unsigned)
  21. struct CallInfo
  22. {
  23. CallInfo() {}
  24. /*
  25. * Removed the copy constructor because it forced the 64 bit compiler
  26. * to pass this object by reference. Interpreter stack setup code expects
  27. * CallInfo to be passed by value.
  28. */
  29. explicit CallInfo(ArgSlot count)
  30. : Flags(CallFlags_None)
  31. , Count(count)
  32. #ifdef TARGET_64
  33. , unused(0)
  34. #endif
  35. {
  36. // Keeping this version to avoid the assert
  37. }
  38. // The bool is used to avoid the signature confusion between the ArgSlot and uint version of the constructor
  39. explicit CallInfo(uint count, bool unusedBool)
  40. : Flags(CallFlags_None)
  41. , Count(count)
  42. #ifdef TARGET_64
  43. , unused(0)
  44. #endif
  45. {
  46. AssertOrFailFastMsg(count < CallInfo::kMaxCountArgs, "Argument list too large");
  47. }
  48. CallInfo(CallFlags flags, uint count)
  49. : Flags(flags)
  50. , Count(count)
  51. #ifdef TARGET_64
  52. , unused(0)
  53. #endif
  54. {
  55. // Keeping this version to avoid the assert
  56. }
  57. CallInfo(VirtualTableInfoCtorEnum v)
  58. {
  59. }
  60. ArgSlot GetArgCountWithExtraArgs() const
  61. {
  62. return CallInfo::GetArgCountWithExtraArgs(this->Flags, this->Count);
  63. }
  64. uint GetLargeArgCountWithExtraArgs() const
  65. {
  66. return CallInfo::GetLargeArgCountWithExtraArgs(this->Flags, this->Count);
  67. }
  68. bool HasExtraArg() const
  69. {
  70. return CallInfo::HasExtraArg(this->Flags);
  71. }
  72. bool HasNewTarget() const
  73. {
  74. return CallInfo::HasNewTarget(this->Flags);
  75. }
  76. static ArgSlot GetArgCountWithExtraArgs(CallFlags flags, uint count);
  77. static uint GetLargeArgCountWithExtraArgs(CallFlags flags, uint count);
  78. static ArgSlot GetArgCountWithoutExtraArgs(CallFlags flags, ArgSlot count);
  79. static bool HasExtraArg(CallFlags flags)
  80. {
  81. // Generally HasNewTarget should not be true if CallFlags_ExtraArg is not set.
  82. Assert(!CallInfo::HasNewTarget(flags) || flags & CallFlags_ExtraArg);
  83. // we will still check HasNewTarget to be safe in case if above invariant does not hold.
  84. return (flags & CallFlags_ExtraArg) || CallInfo::HasNewTarget(flags);
  85. }
  86. static bool HasNewTarget(CallFlags flags)
  87. {
  88. return (flags & CallFlags_NewTarget) == CallFlags_NewTarget;
  89. }
  90. // New target value is passed as an extra argument which is nto included in the Count
  91. static Var GetNewTarget(CallFlags flag, Var* values, uint count)
  92. {
  93. if (HasNewTarget(flag))
  94. {
  95. return values[count];
  96. }
  97. else
  98. {
  99. AssertOrFailFast(count > 0);
  100. return values[0];
  101. }
  102. }
  103. // Assumes big-endian layout
  104. // If the size of the count is changed, change should happen at following places also
  105. // - scriptdirect.idl
  106. // - LowererMDArch::LoadInputParamCount
  107. //
  108. Field(unsigned) Count : 24;
  109. Field(CallFlags) Flags : 8;
  110. #ifdef TARGET_64
  111. Field(unsigned) unused : 32;
  112. #endif
  113. #if DBG
  114. bool operator==(CallInfo other) const
  115. {
  116. return this->Count == other.Count && this->Flags == other.Flags;
  117. }
  118. #endif
  119. public:
  120. static const ushort ksizeofCount;
  121. static const ushort ksizeofCallFlags;
  122. static const uint kMaxCountArgs;
  123. };
  124. struct InlineeCallInfo
  125. {
  126. // Assumes big-endian layout.
  127. uint Count : 4;
  128. #if TARGET_32
  129. uint InlineeStartOffset : 28;
  130. #else
  131. uint unused : 28;
  132. uint InlineeStartOffset;
  133. #endif
  134. static size_t const MaxInlineeArgoutCount = 0xF;
  135. #if TARGET_32
  136. static uint const ksizeofInlineeStartOffset = 28;
  137. #else
  138. static uint const ksizeofInlineeStartOffset = 32;
  139. #endif
  140. static uint const inlineeStartOffsetShiftCount = (sizeof(void*) * CHAR_BIT - Js::InlineeCallInfo::ksizeofInlineeStartOffset);
  141. static bool Encode(intptr_t &callInfo, size_t count, size_t offset)
  142. {
  143. const size_t offsetMask = ~(uint)0 >> (sizeof(uint) * CHAR_BIT - ksizeofInlineeStartOffset);
  144. const size_t countMask = 0x0000000F;
  145. if (count != (count & countMask))
  146. {
  147. return false;
  148. }
  149. if (offset != (offset & offsetMask))
  150. {
  151. return false;
  152. }
  153. callInfo = (offset << inlineeStartOffsetShiftCount) | count;
  154. return true;
  155. }
  156. void Clear()
  157. {
  158. this->Count = 0;
  159. this->InlineeStartOffset = 0;
  160. }
  161. };
  162. }