Symbol.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #include "RuntimeByteCodePch.h"
  6. #if DBG_DUMP
  7. static const char16 * const SymbolTypeNames[] = { _u("Function"), _u("Variable"), _u("MemberName"), _u("Formal"), _u("Unknown") };
  8. #endif
  9. bool Symbol::GetIsArguments() const
  10. {
  11. return decl != nullptr && (decl->grfpn & PNodeFlags::fpnArguments);
  12. }
  13. Js::PropertyId Symbol::EnsurePosition(ByteCodeGenerator* byteCodeGenerator)
  14. {
  15. // Guarantee that a symbol's name has a property ID mapping.
  16. if (this->position == Js::Constants::NoProperty)
  17. {
  18. this->position = this->EnsurePositionNoCheck(byteCodeGenerator->TopFuncInfo());
  19. }
  20. return this->position;
  21. }
  22. Js::PropertyId Symbol::EnsurePosition(FuncInfo *funcInfo)
  23. {
  24. // Guarantee that a symbol's name has a property ID mapping.
  25. if (this->position == Js::Constants::NoProperty)
  26. {
  27. this->position = this->EnsurePositionNoCheck(funcInfo);
  28. }
  29. return this->position;
  30. }
  31. Js::PropertyId Symbol::EnsurePositionNoCheck(FuncInfo *funcInfo)
  32. {
  33. return funcInfo->byteCodeFunction->GetOrAddPropertyIdTracked(this->GetName());
  34. }
  35. void Symbol::SaveToPropIdArray(Symbol *sym, Js::PropertyIdArray *propIds, ByteCodeGenerator *byteCodeGenerator, Js::PropertyId *pFirstSlot /* = null */)
  36. {
  37. if (sym)
  38. {
  39. Js::PropertyId slot = sym->scopeSlot;
  40. if (slot != Js::Constants::NoProperty)
  41. {
  42. Assert((uint32)slot < propIds->count);
  43. propIds->elements[slot] = sym->EnsurePosition(byteCodeGenerator);
  44. if (pFirstSlot && !sym->GetIsArguments())
  45. {
  46. if (*pFirstSlot == Js::Constants::NoProperty ||
  47. *pFirstSlot > slot)
  48. {
  49. *pFirstSlot = slot;
  50. }
  51. }
  52. }
  53. }
  54. }
  55. bool Symbol::NeedsSlotAlloc(FuncInfo *funcInfo)
  56. {
  57. return IsInSlot(funcInfo, true);
  58. }
  59. bool Symbol::IsInSlot(FuncInfo *funcInfo, bool ensureSlotAlloc)
  60. {
  61. if (this->GetIsGlobal() || this->GetIsModuleExportStorage())
  62. {
  63. return false;
  64. }
  65. if (funcInfo->GetHasHeapArguments() && this->GetIsFormal() && ByteCodeGenerator::NeedScopeObjectForArguments(funcInfo, funcInfo->root))
  66. {
  67. return true;
  68. }
  69. if (this->GetIsGlobalCatch())
  70. {
  71. return true;
  72. }
  73. if (this->scope->GetCapturesAll())
  74. {
  75. return true;
  76. }
  77. return this->GetHasNonLocalReference() && (ensureSlotAlloc || this->GetIsCommittedToSlot());
  78. }
  79. bool Symbol::GetIsCommittedToSlot() const
  80. {
  81. if (!PHASE_ON1(Js::DelayCapturePhase))
  82. {
  83. return true;
  84. }
  85. return isCommittedToSlot || this->scope->GetFunc()->GetCallsEval() || this->scope->GetFunc()->GetChildCallsEval();
  86. }
  87. Js::PropertyId Symbol::EnsureScopeSlot(FuncInfo *funcInfo)
  88. {
  89. if (this->NeedsSlotAlloc(funcInfo) && this->scopeSlot == Js::Constants::NoProperty)
  90. {
  91. this->scopeSlot = this->scope->AddScopeSlot();
  92. }
  93. return this->scopeSlot;
  94. }
  95. void Symbol::SetHasNonLocalReference()
  96. {
  97. this->hasNonLocalReference = true;
  98. this->scope->SetHasOwnLocalInClosure(true);
  99. }
  100. void Symbol::SetHasMaybeEscapedUse(ByteCodeGenerator * byteCodeGenerator)
  101. {
  102. Assert(!this->GetIsMember());
  103. if (!hasMaybeEscapedUse)
  104. {
  105. SetHasMaybeEscapedUseInternal(byteCodeGenerator);
  106. }
  107. }
  108. void Symbol::SetHasMaybeEscapedUseInternal(ByteCodeGenerator * byteCodeGenerator)
  109. {
  110. Assert(!hasMaybeEscapedUse);
  111. Assert(!this->GetIsFormal());
  112. hasMaybeEscapedUse = true;
  113. if (PHASE_TESTTRACE(Js::StackFuncPhase, byteCodeGenerator->TopFuncInfo()->byteCodeFunction))
  114. {
  115. Output::Print(_u("HasMaybeEscapedUse: %s\n"), this->GetName().GetBuffer());
  116. Output::Flush();
  117. }
  118. if (this->GetHasFuncAssignment())
  119. {
  120. this->GetScope()->GetFunc()->SetHasMaybeEscapedNestedFunc(
  121. DebugOnly(this->symbolType == STFunction ? _u("MaybeEscapedUseFuncDecl") : _u("MaybeEscapedUse")));
  122. }
  123. }
  124. void Symbol::SetHasFuncAssignment(ByteCodeGenerator * byteCodeGenerator)
  125. {
  126. Assert(!this->GetIsMember());
  127. if (!hasFuncAssignment)
  128. {
  129. SetHasFuncAssignmentInternal(byteCodeGenerator);
  130. }
  131. }
  132. void Symbol::SetHasFuncAssignmentInternal(ByteCodeGenerator * byteCodeGenerator)
  133. {
  134. Assert(!hasFuncAssignment);
  135. hasFuncAssignment = true;
  136. FuncInfo * top = byteCodeGenerator->TopFuncInfo();
  137. if (PHASE_TESTTRACE(Js::StackFuncPhase, top->byteCodeFunction))
  138. {
  139. Output::Print(_u("HasFuncAssignment: %s\n"), this->GetName().GetBuffer());
  140. Output::Flush();
  141. }
  142. if (this->GetHasMaybeEscapedUse() || this->GetScope()->GetIsObject())
  143. {
  144. byteCodeGenerator->TopFuncInfo()->SetHasMaybeEscapedNestedFunc(DebugOnly(
  145. this->GetIsFormal() ? _u("FormalAssignment") :
  146. this->GetScope()->GetIsObject() ? _u("ObjectScopeAssignment") :
  147. _u("MaybeEscapedUse")));
  148. }
  149. }
  150. void Symbol::RestoreHasFuncAssignment()
  151. {
  152. Assert(hasFuncAssignment == (this->symbolType == STFunction));
  153. Assert(this->GetIsFormal() || !this->GetHasMaybeEscapedUse());
  154. hasFuncAssignment = true;
  155. if (PHASE_TESTTRACE1(Js::StackFuncPhase))
  156. {
  157. Output::Print(_u("RestoreHasFuncAssignment: %s\n"), this->GetName().GetBuffer());
  158. Output::Flush();
  159. }
  160. }
  161. Symbol * Symbol::GetFuncScopeVarSym() const
  162. {
  163. if (!this->GetIsBlockVar())
  164. {
  165. return nullptr;
  166. }
  167. FuncInfo * parentFuncInfo = this->GetScope()->GetFunc();
  168. if (parentFuncInfo->GetIsStrictMode())
  169. {
  170. return nullptr;
  171. }
  172. Symbol *fncScopeSym = parentFuncInfo->GetBodyScope()->FindLocalSymbol(this->GetName());
  173. if (fncScopeSym == nullptr && parentFuncInfo->GetParamScope() != nullptr)
  174. {
  175. // We couldn't find the sym in the body scope, try finding it in the parameter scope.
  176. Scope* paramScope = parentFuncInfo->GetParamScope();
  177. fncScopeSym = paramScope->FindLocalSymbol(this->GetName());
  178. }
  179. // Parser should have added a fake var decl node for block scoped functions in non-strict mode
  180. // IsBlockVar() indicates a user let declared variable at function scope which
  181. // shadows the function's var binding, thus only emit the var binding init if
  182. // we do not have a block var symbol.
  183. if (!fncScopeSym || fncScopeSym->GetIsBlockVar())
  184. {
  185. return nullptr;
  186. }
  187. return fncScopeSym;
  188. }
  189. #if DBG_DUMP
  190. const char16 * Symbol::GetSymbolTypeName()
  191. {
  192. return SymbolTypeNames[symbolType];
  193. }
  194. #endif