ScopeInfo.cpp 11 KB

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