ScopeInfo.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. namespace Js
  7. {
  8. //
  9. // Persist one symbol info into ScopeInfo.
  10. //
  11. void ScopeInfo::SaveSymbolInfo(Symbol* sym, MapSymbolData* mapSymbolData)
  12. {
  13. // We don't need to create slot for or save "arguments"
  14. bool needScopeSlot = !sym->GetIsArguments() && sym->GetHasNonLocalReference();
  15. Js::PropertyId scopeSlot = Constants::NoSlot;
  16. if (sym->GetIsModuleExportStorage())
  17. {
  18. // Export symbols aren't in slots but we need to persist the fact that they are export storage
  19. scopeSlot = sym->GetScope()->GetScopeSlotCount() + mapSymbolData->nonScopeSymbolCount++;
  20. }
  21. else if (needScopeSlot)
  22. {
  23. // Any symbol may have non-local ref from deferred child. Allocate slot for it.
  24. scopeSlot = sym->EnsureScopeSlot(mapSymbolData->func);
  25. }
  26. if (needScopeSlot || sym->GetIsModuleExportStorage())
  27. {
  28. Js::PropertyId propertyId = sym->EnsurePosition(mapSymbolData->func);
  29. this->SetSymbolId(scopeSlot, propertyId);
  30. this->SetSymbolType(scopeSlot, sym->GetSymbolType());
  31. this->SetHasFuncAssignment(scopeSlot, sym->GetHasFuncAssignment());
  32. this->SetIsBlockVariable(scopeSlot, sym->GetIsBlockVar());
  33. this->SetIsFuncExpr(scopeSlot, sym->GetIsFuncExpr());
  34. this->SetIsModuleExportStorage(scopeSlot, sym->GetIsModuleExportStorage());
  35. this->SetIsModuleImport(scopeSlot, sym->GetIsModuleImport());
  36. }
  37. TRACE_BYTECODE(_u("%12s %d\n"), sym->GetName().GetBuffer(), sym->GetScopeSlot());
  38. }
  39. inline void AddSlotCount(int& count, int addCount)
  40. {
  41. if (addCount != 0 && Int32Math::Add(count, addCount, &count))
  42. {
  43. ::Math::DefaultOverflowPolicy();
  44. }
  45. }
  46. //
  47. // Create scope info for a single scope.
  48. //
  49. ScopeInfo* ScopeInfo::SaveOneScopeInfo(/*ByteCodeGenerator* byteCodeGenerator, ParseableFunctionInfo* parent,*/ Scope* scope, ScriptContext *scriptContext)
  50. {
  51. Assert(scope->GetScopeInfo() == nullptr);
  52. Assert(scope->GetScopeType() != ScopeType_Global);
  53. int count = scope->Count();
  54. // Add argsPlaceHolder which includes same name args and destructuring patterns on parameters
  55. AddSlotCount(count, scope->GetFunc()->argsPlaceHolderSlotCount);
  56. AddSlotCount(count, scope->GetFunc()->thisScopeSlot != Js::Constants::NoRegister ? 1 : 0);
  57. AddSlotCount(count, scope->GetFunc()->superScopeSlot != Js::Constants::NoRegister ? 1 : 0);
  58. AddSlotCount(count, scope->GetFunc()->newTargetScopeSlot != Js::Constants::NoRegister ? 1 : 0);
  59. ScopeInfo* scopeInfo = RecyclerNewPlusZ(scriptContext->GetRecycler(),
  60. count * sizeof(SymbolInfo),
  61. ScopeInfo, scope->GetFunc()->byteCodeFunction->GetFunctionInfo(),/*parent ? parent->GetFunctionInfo() : nullptr,*/ count);
  62. scopeInfo->SetScopeType(scope->GetScopeType());
  63. scopeInfo->isDynamic = scope->GetIsDynamic();
  64. scopeInfo->isObject = scope->GetIsObject();
  65. scopeInfo->mustInstantiate = scope->GetMustInstantiate();
  66. scopeInfo->isCached = (scope->GetFunc()->GetBodyScope() == scope) && scope->GetFunc()->GetHasCachedScope();
  67. scopeInfo->hasLocalInClosure = scope->GetHasOwnLocalInClosure();
  68. TRACE_BYTECODE(_u("\nSave ScopeInfo: %s #symbols: %d %s\n"),
  69. scope->GetFunc()->name, count,
  70. scopeInfo->isObject ? _u("isObject") : _u(""));
  71. MapSymbolData mapSymbolData = { scope->GetFunc(), 0 };
  72. scope->ForEachSymbol([&mapSymbolData, scopeInfo, scope](Symbol * sym)
  73. {
  74. Assert(scope == sym->GetScope());
  75. scopeInfo->SaveSymbolInfo(sym, &mapSymbolData);
  76. });
  77. scope->SetScopeInfo(scopeInfo);
  78. return scopeInfo;
  79. }
  80. //
  81. // Ensure the pids referenced by this scope are tracked.
  82. //
  83. void ScopeInfo::EnsurePidTracking(ScriptContext* scriptContext)
  84. {
  85. for (int i = 0; i < symbolCount; i++)
  86. {
  87. auto propertyName = scriptContext->GetPropertyName(symbols[i].propertyId);
  88. scriptContext->TrackPid(propertyName);
  89. }
  90. }
  91. //
  92. // Save scope info for an individual scope and link it to its enclosing scope.
  93. //
  94. ScopeInfo * ScopeInfo::SaveScopeInfo(Scope * scope/*ByteCodeGenerator* byteCodeGenerator, FuncInfo* parentFunc, FuncInfo* func*/, ScriptContext * scriptContext)
  95. {
  96. // Advance past scopes that will be excluded from the closure environment. (But note that we always want the body scope.)
  97. while (scope && (!scope->GetMustInstantiate() && scope != scope->GetFunc()->GetBodyScope()))
  98. {
  99. scope = scope->GetEnclosingScope();
  100. }
  101. // If we've exhausted the scope chain, we're done.
  102. if (scope == nullptr || scope->GetScopeType() == ScopeType_Global)
  103. {
  104. return nullptr;
  105. }
  106. // If we've already collected info for this scope, we're done.
  107. ScopeInfo * scopeInfo = scope->GetScopeInfo();
  108. if (scopeInfo != nullptr)
  109. {
  110. return scopeInfo;
  111. }
  112. // Do the work for this scope.
  113. scopeInfo = ScopeInfo::SaveOneScopeInfo(scope, scriptContext);
  114. // Link to the parent (if any).
  115. scope = scope->GetEnclosingScope();
  116. if (scope)
  117. {
  118. scopeInfo->SetParentScopeInfo(ScopeInfo::SaveScopeInfo(scope, scriptContext));
  119. }
  120. return scopeInfo;
  121. }
  122. void ScopeInfo::SaveEnclosingScopeInfo(ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo)
  123. {
  124. // TODO: Not technically necessary, as we always do scope look up on eval if it is
  125. // not found in the scope chain, and block scopes are always objects in eval.
  126. // But if we save the global eval block scope for deferred child so that we can look up
  127. // let/const in that scope with slot index instead of doing a scope lookup.
  128. // We will have to implement encoding block scope info to enable, which will also
  129. // enable defer parsing function that are in block scopes.
  130. if (funcInfo->byteCodeFunction &&
  131. funcInfo->byteCodeFunction->GetScopeInfo() != nullptr)
  132. {
  133. // No need to regenerate scope info if we re-compile an enclosing function
  134. return;
  135. }
  136. Scope* currentScope = byteCodeGenerator->GetCurrentScope();
  137. Assert(currentScope->GetFunc() == funcInfo);
  138. while (currentScope->GetFunc() == funcInfo)
  139. {
  140. currentScope = currentScope->GetEnclosingScope();
  141. }
  142. ScopeInfo * scopeInfo = ScopeInfo::SaveScopeInfo(currentScope, byteCodeGenerator->GetScriptContext());
  143. if (scopeInfo != nullptr)
  144. {
  145. funcInfo->byteCodeFunction->SetScopeInfo(scopeInfo);
  146. }
  147. }
  148. //
  149. // Load persisted scope info.
  150. //
  151. void ScopeInfo::ExtractScopeInfo(Parser *parser, /*ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo,*/ Scope* scope)
  152. {
  153. ScriptContext* scriptContext;
  154. ArenaAllocator* alloc;
  155. // Load scope attributes and push onto scope stack.
  156. scope->SetMustInstantiate(this->mustInstantiate);
  157. scope->SetHasOwnLocalInClosure(this->hasLocalInClosure);
  158. scope->SetIsDynamic(this->isDynamic);
  159. if (this->isObject)
  160. {
  161. scope->SetIsObject();
  162. }
  163. Assert(parser);
  164. scriptContext = parser->GetScriptContext();
  165. alloc = parser->GetAllocator();
  166. // Load scope symbols
  167. // On first access to the scopeinfo, replace the ID's with PropertyRecord*'s to save the dictionary lookup
  168. // on later accesses. Replace them all before allocating Symbol's to prevent inconsistency on OOM.
  169. if (!this->areNamesCached && !PHASE_OFF1(Js::CacheScopeInfoNamesPhase))
  170. {
  171. for (int i = 0; i < symbolCount; i++)
  172. {
  173. PropertyId propertyId = GetSymbolId(i);
  174. if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot
  175. {
  176. PropertyRecord const* name = scriptContext->GetPropertyName(propertyId);
  177. this->SetPropertyName(i, name);
  178. }
  179. }
  180. this->areNamesCached = true;
  181. }
  182. for (int i = 0; i < symbolCount; i++)
  183. {
  184. PropertyRecord const* name = nullptr;
  185. if (this->areNamesCached)
  186. {
  187. name = this->GetPropertyName(i);
  188. }
  189. else
  190. {
  191. PropertyId propertyId = GetSymbolId(i);
  192. if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot
  193. {
  194. name = scriptContext->GetPropertyName(propertyId);
  195. }
  196. }
  197. if (name != nullptr)
  198. {
  199. SymbolType symbolType = GetSymbolType(i);
  200. SymbolName symName(name->GetBuffer(), name->GetLength());
  201. Symbol *sym = Anew(alloc, Symbol, symName, nullptr, symbolType);
  202. sym->SetScopeSlot(static_cast<PropertyId>(i));
  203. sym->SetIsBlockVar(GetIsBlockVariable(i));
  204. sym->SetIsFuncExpr(GetIsFuncExpr(i));
  205. sym->SetIsModuleExportStorage(GetIsModuleExportStorage(i));
  206. sym->SetIsModuleImport(GetIsModuleImport(i));
  207. if (GetHasFuncAssignment(i))
  208. {
  209. sym->RestoreHasFuncAssignment();
  210. }
  211. scope->AddNewSymbol(sym);
  212. sym->SetHasNonLocalReference();
  213. Assert(parser);
  214. parser->RestorePidRefForSym(sym);
  215. TRACE_BYTECODE(_u("%12s %d\n"), sym->GetName().GetBuffer(), sym->GetScopeSlot());
  216. }
  217. }
  218. this->scope = scope;
  219. DebugOnly(scope->isRestored = true);
  220. }
  221. ScopeInfo::AutoCapturesAllScope::AutoCapturesAllScope(Scope* scope, bool turnOn)
  222. : scope(scope)
  223. {
  224. oldCapturesAll = scope->GetCapturesAll();
  225. if (turnOn)
  226. {
  227. scope->SetCapturesAll(true);
  228. }
  229. }
  230. ScopeInfo::AutoCapturesAllScope::~AutoCapturesAllScope()
  231. {
  232. scope->SetCapturesAll(oldCapturesAll);
  233. }
  234. } // namespace Js