Symbol.cpp 6.9 KB

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