FuncInfo.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  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. struct InlineCacheUnit
  6. {
  7. InlineCacheUnit() : loadCacheId((uint)-1), loadMethodCacheId((uint)-1), storeCacheId((uint)-1) {}
  8. union {
  9. struct {
  10. uint loadCacheId;
  11. uint loadMethodCacheId;
  12. uint storeCacheId;
  13. };
  14. struct {
  15. uint cacheId;
  16. };
  17. };
  18. };
  19. typedef JsUtil::BaseDictionary<ParseNode*, SList<Symbol*>*, ArenaAllocator, PowerOf2SizePolicy> CapturedSymMap;
  20. class FuncInfo
  21. {
  22. private:
  23. struct SlotKey
  24. {
  25. Scope* scope;
  26. Js::PropertyId slot;
  27. };
  28. template<class TSlotKey>
  29. class SlotKeyComparer
  30. {
  31. public:
  32. static bool Equals(TSlotKey key1, TSlotKey key2)
  33. {
  34. return (key1.scope == key2.scope && key1.slot == key2.slot);
  35. }
  36. static int GetHashCode(TSlotKey key)
  37. {
  38. return ::Math::PointerCastToIntegralTruncate<int>(key.scope) | key.slot & ArenaAllocator::ObjectAlignmentMask;
  39. }
  40. };
  41. uint inlineCacheCount;
  42. uint rootObjectLoadInlineCacheCount;
  43. uint rootObjectLoadMethodInlineCacheCount;
  44. uint rootObjectStoreInlineCacheCount;
  45. uint isInstInlineCacheCount;
  46. uint referencedPropertyIdCount;
  47. uint NewInlineCache()
  48. {
  49. AssertMsg(this->inlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
  50. return inlineCacheCount++;
  51. }
  52. uint NewRootObjectLoadInlineCache()
  53. {
  54. AssertMsg(this->rootObjectLoadInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
  55. return rootObjectLoadInlineCacheCount++;
  56. }
  57. uint NewRootObjectLoadMethodInlineCache()
  58. {
  59. AssertMsg(this->rootObjectLoadMethodInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
  60. return rootObjectLoadMethodInlineCacheCount++;
  61. }
  62. uint NewRootObjectStoreInlineCache()
  63. {
  64. AssertMsg(this->rootObjectStoreInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
  65. return rootObjectStoreInlineCacheCount++;
  66. }
  67. uint NewReferencedPropertyId()
  68. {
  69. AssertMsg(this->referencedPropertyIdCount < (uint)-2, "Referenced Property Id index wrapped around?");
  70. return referencedPropertyIdCount++;
  71. }
  72. FuncInfo *currentChildFunction;
  73. Scope *currentChildScope;
  74. SymbolTable *capturedSyms;
  75. CapturedSymMap *capturedSymMap;
  76. uint nextForInLoopLevel;
  77. uint maxForInLoopLevel;
  78. public:
  79. static const Js::RegSlot InitialConstRegsCount = 2; // constRegsCount is set to 2 because R0 is the return register, and R1 is the root object
  80. ArenaAllocator *alloc;
  81. // set in Bind/Assign pass
  82. Js::RegSlot varRegsCount; // number of registers used for non-constants
  83. Js::RegSlot constRegsCount; // number of registers used for constants
  84. Js::ArgSlot inArgsCount; // number of in args (including 'this')
  85. Js::RegSlot outArgsMaxDepth; // max depth of out args stack
  86. Js::RegSlot outArgsCurrentExpr; // max number of out args accumulated in the current nested expression
  87. uint innerScopeCount;
  88. uint currentInnerScopeIndex;
  89. #if DBG
  90. uint32 outArgsDepth; // number of calls nested in an expression
  91. #endif
  92. const char16 *name; // name of the function
  93. Js::RegSlot nullConstantRegister; // location, if any, of enregistered null constant
  94. Js::RegSlot undefinedConstantRegister; // location, if any, of enregistered undefined constant
  95. Js::RegSlot trueConstantRegister; // location, if any, of enregistered true constant
  96. Js::RegSlot falseConstantRegister; // location, if any, of enregistered false constant
  97. Js::RegSlot thisPointerRegister; // location, if any, of this pointer
  98. Js::RegSlot superRegister; // location, if any, of the super reference
  99. Js::RegSlot superCtorRegister; // location, if any, of the superCtor reference
  100. Js::RegSlot newTargetRegister; // location, if any, of the new.target reference
  101. private:
  102. Js::RegSlot envRegister; // location, if any, of the closure environment
  103. public:
  104. Js::RegSlot frameObjRegister; // location, if any, of the heap-allocated local frame
  105. Js::RegSlot frameSlotsRegister; // location, if any, of the heap-allocated local frame
  106. Js::RegSlot paramSlotsRegister; // location, if any, of the heap allocated local frame for param scope
  107. Js::RegSlot frameDisplayRegister; // location, if any, of the display of nested frames
  108. Js::RegSlot funcObjRegister;
  109. Js::RegSlot localClosureReg;
  110. Js::RegSlot yieldRegister;
  111. Js::RegSlot firstTmpReg;
  112. Js::RegSlot curTmpReg;
  113. int argsPlaceHolderSlotCount; // count of place holder slots for same name args and destructuring patterns
  114. Js::RegSlot firstThunkArgReg;
  115. short thunkArgCount;
  116. short staticFuncId;
  117. uint callsEval : 1;
  118. uint childCallsEval : 1;
  119. uint hasArguments : 1;
  120. uint hasHeapArguments : 1;
  121. uint isTopLevelEventHandler : 1;
  122. uint hasLocalInClosure : 1;
  123. uint hasClosureReference : 1;
  124. uint hasGlobalReference : 1;
  125. uint hasCachedScope : 1;
  126. uint funcExprNameReference : 1;
  127. uint applyEnclosesArgs : 1;
  128. uint escapes : 1;
  129. uint hasDeferredChild : 1; // switch for DeferNested to persist outer scopes
  130. uint hasRedeferrableChild : 1;
  131. uint childHasWith : 1; // deferNested needs to know if child has with
  132. uint hasLoop : 1;
  133. uint hasEscapedUseNestedFunc : 1;
  134. uint needEnvRegister : 1;
  135. uint hasCapturedThis : 1;
  136. uint isBodyAndParamScopeMerged : 1;
  137. #if DBG
  138. // FunctionBody was reused on recompile of a redeferred enclosing function.
  139. uint isReused:1;
  140. #endif
  141. typedef JsUtil::BaseDictionary<uint, Js::RegSlot, ArenaAllocator, PrimeSizePolicy> ConstantRegisterMap;
  142. ConstantRegisterMap constantToRegister; // maps uint constant to register
  143. typedef JsUtil::BaseDictionary<IdentPtr, Js::RegSlot, ArenaAllocator> PidRegisterMap;
  144. PidRegisterMap stringToRegister; // maps string constant to register
  145. typedef JsUtil::BaseDictionary<double,Js::RegSlot, ArenaAllocator, PrimeSizePolicy> DoubleRegisterMap;
  146. DoubleRegisterMap doubleConstantToRegister; // maps double constant to register
  147. typedef JsUtil::BaseDictionary<ParseNodePtr, Js::RegSlot, ArenaAllocator, PowerOf2SizePolicy, Js::StringTemplateCallsiteObjectComparer> StringTemplateCallsiteRegisterMap;
  148. StringTemplateCallsiteRegisterMap stringTemplateCallsiteRegisterMap; // maps string template callsite constant to register
  149. Scope *paramScope; // top level scope for parameter default values
  150. Scope *bodyScope; // top level scope of the function body
  151. Scope *funcExprScope;
  152. ParseNode *root; // top-level AST for function
  153. Js::ParseableFunctionInfo* byteCodeFunction; // reference to generated bytecode function (could be defer parsed or actually parsed)
  154. SList<ParseNode*> targetStatements; // statements that are targets of jumps (break or continue)
  155. Js::ByteCodeLabel singleExit;
  156. typedef SList<InlineCacheUnit> InlineCacheList;
  157. typedef JsUtil::BaseDictionary<Js::PropertyId, InlineCacheList*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheIdMap;
  158. typedef JsUtil::BaseDictionary<Js::RegSlot, InlineCacheIdMap*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheMap;
  159. typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> RootObjectInlineCacheIdMap;
  160. typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> ReferencedPropertyIdMap;
  161. RootObjectInlineCacheIdMap * rootObjectLoadInlineCacheMap;
  162. RootObjectInlineCacheIdMap * rootObjectLoadMethodInlineCacheMap;
  163. RootObjectInlineCacheIdMap * rootObjectStoreInlineCacheMap;
  164. InlineCacheMap * inlineCacheMap;
  165. ReferencedPropertyIdMap * referencedPropertyIdToMapIndex;
  166. SListBase<uint> valueOfStoreCacheIds;
  167. SListBase<uint> toStringStoreCacheIds;
  168. typedef JsUtil::BaseDictionary<SlotKey, Js::ProfileId, ArenaAllocator, PowerOf2SizePolicy, SlotKeyComparer> SlotProfileIdMap;
  169. SlotProfileIdMap slotProfileIdMap;
  170. Js::PropertyId thisScopeSlot;
  171. Js::PropertyId superScopeSlot;
  172. Js::PropertyId superCtorScopeSlot;
  173. Js::PropertyId newTargetScopeSlot;
  174. bool isThisLexicallyCaptured;
  175. bool isSuperLexicallyCaptured;
  176. bool isSuperCtorLexicallyCaptured;
  177. bool isNewTargetLexicallyCaptured;
  178. Symbol *argumentsSymbol;
  179. JsUtil::List<Js::RegSlot, ArenaAllocator> nonUserNonTempRegistersToInitialize;
  180. FuncInfo(
  181. const char16 *name,
  182. ArenaAllocator *alloc,
  183. Scope *paramScope,
  184. Scope *bodyScope,
  185. ParseNode *pnode,
  186. Js::ParseableFunctionInfo* byteCodeFunction);
  187. uint NewIsInstInlineCache() { return isInstInlineCacheCount++; }
  188. uint GetInlineCacheCount() const { return this->inlineCacheCount; }
  189. uint GetRootObjectLoadInlineCacheCount() const { return this->rootObjectLoadInlineCacheCount; }
  190. uint GetRootObjectLoadMethodInlineCacheCount() const { return this->rootObjectLoadMethodInlineCacheCount; }
  191. uint GetRootObjectStoreInlineCacheCount() const { return this->rootObjectStoreInlineCacheCount; }
  192. uint GetIsInstInlineCacheCount() const { return this->isInstInlineCacheCount; }
  193. uint GetReferencedPropertyIdCount() const { return this->referencedPropertyIdCount; }
  194. void SetFirstTmpReg(Js::RegSlot tmpReg)
  195. {
  196. Assert(this->firstTmpReg == Js::Constants::NoRegister);
  197. Assert(this->curTmpReg == Js::Constants::NoRegister);
  198. this->firstTmpReg = tmpReg;
  199. this->curTmpReg = tmpReg;
  200. }
  201. bool IsTmpReg(Js::RegSlot tmpReg)
  202. {
  203. Assert(this->firstTmpReg != Js::Constants::NoRegister);
  204. return !RegIsConst(tmpReg) && tmpReg >= firstTmpReg;
  205. }
  206. bool RegIsConst(Js::RegSlot reg)
  207. {
  208. // varRegsCount includes the tmp regs, so if reg number is larger than that,
  209. // then it must be in the negative range for const.
  210. return reg >= varRegsCount;
  211. }
  212. Js::RegSlot NextVarRegister()
  213. {
  214. AssertMsg(this->firstTmpReg == Js::Constants::NoRegister, "Shouldn't assign var register after we start allocating temp reg");
  215. Js::RegSlot reg = varRegsCount;
  216. UInt32Math::Inc(varRegsCount);
  217. return REGSLOT_TO_VARREG(reg);
  218. }
  219. Js::RegSlot NextConstRegister()
  220. {
  221. AssertMsg(this->firstTmpReg == Js::Constants::NoRegister, "Shouldn't assign var register after we start allocating temp reg");
  222. Js::RegSlot reg = constRegsCount;
  223. UInt32Math::Inc(constRegsCount);
  224. return REGSLOT_TO_CONSTREG(reg);
  225. }
  226. Js::RegSlot RegCount() const
  227. {
  228. return constRegsCount + varRegsCount;
  229. }
  230. uint InnerScopeCount() const { return innerScopeCount; }
  231. uint CurrentInnerScopeIndex() const { return currentInnerScopeIndex; }
  232. uint AcquireInnerScopeIndex();
  233. void ReleaseInnerScopeIndex();
  234. bool GetApplyEnclosesArgs() const { return applyEnclosesArgs; }
  235. void SetApplyEnclosesArgs(bool b) { applyEnclosesArgs=b; }
  236. bool IsGlobalFunction() const;
  237. // Fake global ->
  238. // 1) new Function code's global code
  239. // 2) global code generated from the reparsing deferred parse function
  240. bool IsFakeGlobalFunction(uint32 flags) const {
  241. return IsGlobalFunction() && !(flags & fscrGlobalCode);
  242. }
  243. Scope *GetBodyScope() const {
  244. return bodyScope;
  245. }
  246. Scope *GetParamScope() const {
  247. return paramScope;
  248. }
  249. Scope *GetTopLevelScope() const {
  250. // Top level scope will be the same for knopProg and knopFncDecl.
  251. return paramScope;
  252. }
  253. Scope* GetFuncExprScope() const {
  254. return funcExprScope;
  255. }
  256. void SetFuncExprScope(Scope* funcExprScope) {
  257. this->funcExprScope = funcExprScope;
  258. }
  259. Symbol *GetArgumentsSymbol() const
  260. {
  261. return argumentsSymbol;
  262. }
  263. void SetArgumentsSymbol(Symbol *sym)
  264. {
  265. Assert(argumentsSymbol == nullptr || argumentsSymbol == sym);
  266. argumentsSymbol = sym;
  267. }
  268. bool GetCallsEval() const {
  269. return callsEval;
  270. }
  271. void SetCallsEval(bool does) {
  272. callsEval = does;
  273. }
  274. bool GetHasArguments() const {
  275. return hasArguments;
  276. }
  277. void SetHasArguments(bool has) {
  278. hasArguments = has;
  279. }
  280. bool GetHasHeapArguments() const
  281. {
  282. return hasHeapArguments;
  283. }
  284. void SetHasHeapArguments(bool has, bool optArgInBackend = false)
  285. {
  286. hasHeapArguments = has;
  287. byteCodeFunction->SetDoBackendArgumentsOptimization(optArgInBackend);
  288. }
  289. bool GetIsTopLevelEventHandler() const {
  290. return isTopLevelEventHandler;
  291. }
  292. void SetIsTopLevelEventHandler(bool is) {
  293. isTopLevelEventHandler = is;
  294. }
  295. bool GetChildCallsEval() const {
  296. return childCallsEval;
  297. }
  298. void SetChildCallsEval(bool does) {
  299. childCallsEval = does;
  300. }
  301. bool GetHasLocalInClosure() const {
  302. return hasLocalInClosure;
  303. }
  304. void SetHasLocalInClosure(bool has) {
  305. hasLocalInClosure = has;
  306. }
  307. bool GetHasClosureReference() const {
  308. return hasClosureReference;
  309. }
  310. void SetHasCachedScope(bool has) {
  311. hasCachedScope = has;
  312. }
  313. bool GetHasCachedScope() const {
  314. return hasCachedScope;
  315. }
  316. void SetFuncExprNameReference(bool has) {
  317. funcExprNameReference = has;
  318. }
  319. bool GetFuncExprNameReference() const {
  320. return funcExprNameReference;
  321. }
  322. void SetHasClosureReference(bool has) {
  323. hasClosureReference = has;
  324. }
  325. bool GetHasGlobalRef() const {
  326. return hasGlobalReference;
  327. }
  328. void SetHasGlobalRef(bool has) {
  329. hasGlobalReference = has;
  330. }
  331. bool GetIsStrictMode() const {
  332. return this->byteCodeFunction->GetIsStrictMode();
  333. }
  334. bool Escapes() const {
  335. return escapes;
  336. }
  337. void SetEscapes(bool does) {
  338. escapes = does;
  339. }
  340. bool HasMaybeEscapedNestedFunc() const {
  341. return hasEscapedUseNestedFunc;
  342. }
  343. void SetHasMaybeEscapedNestedFunc(DebugOnly(char16 const * reason));
  344. bool IsDeferred() const;
  345. bool IsRestored()
  346. {
  347. // FuncInfo are from RestoredScopeInfo
  348. return root == nullptr;
  349. }
  350. bool HasDeferredChild() const {
  351. return hasDeferredChild;
  352. }
  353. void SetHasDeferredChild() {
  354. hasDeferredChild = true;
  355. }
  356. bool HasRedeferrableChild() const {
  357. return hasRedeferrableChild;
  358. }
  359. void SetHasRedeferrableChild() {
  360. hasRedeferrableChild = true;
  361. }
  362. bool IsRedeferrable() const;
  363. Js::FunctionBody* GetParsedFunctionBody() const
  364. {
  365. AssertMsg(this->byteCodeFunction->IsFunctionParsed(), "Function must be parsed in order to call this method");
  366. Assert(!IsDeferred() || this->byteCodeFunction->GetFunctionBody()->GetByteCode() != nullptr);
  367. return this->byteCodeFunction->GetFunctionBody();
  368. }
  369. bool ChildHasWith() const {
  370. return childHasWith;
  371. }
  372. void SetChildHasWith() {
  373. childHasWith = true;
  374. }
  375. bool HasCapturedThis() const {
  376. return hasCapturedThis;
  377. }
  378. void SetHasCapturedThis() {
  379. hasCapturedThis = true;
  380. }
  381. bool IsBodyAndParamScopeMerged() const {
  382. return isBodyAndParamScopeMerged;
  383. }
  384. void ResetBodyAndParamScopeMerged() {
  385. isBodyAndParamScopeMerged = false;
  386. }
  387. BOOL HasSuperReference() const;
  388. BOOL HasDirectSuper() const;
  389. BOOL IsClassMember() const;
  390. BOOL IsLambda() const;
  391. BOOL IsClassConstructor() const;
  392. BOOL IsBaseClassConstructor() const;
  393. void RemoveTargetStmt(ParseNode* pnodeStmt) {
  394. targetStatements.Remove(pnodeStmt);
  395. }
  396. void AddTargetStmt(ParseNode *pnodeStmt) {
  397. targetStatements.Prepend(pnodeStmt);
  398. }
  399. Js::RegSlot LookupDouble(double d) {
  400. return doubleConstantToRegister.Lookup(d,Js::Constants::NoRegister);
  401. }
  402. bool TryGetDoubleLoc(double d, Js::RegSlot *loc) {
  403. Js::RegSlot ret=LookupDouble(d);
  404. *loc=ret;
  405. return(ret!=Js::Constants::NoRegister);
  406. }
  407. void AddDoubleConstant(double d, Js::RegSlot location) {
  408. doubleConstantToRegister.Item(d,location);
  409. }
  410. bool NeedEnvRegister() const { return this->needEnvRegister; }
  411. void SetNeedEnvRegister() { this->needEnvRegister = true; };
  412. Js::RegSlot GetEnvRegister() const
  413. {
  414. Assert(this->envRegister != Js::Constants::NoRegister);
  415. return this->envRegister;
  416. }
  417. Js::RegSlot AssignEnvRegister(bool constReg)
  418. {
  419. Assert(needEnvRegister);
  420. Assert(this->envRegister == Js::Constants::NoRegister);
  421. Js::RegSlot reg = constReg? NextConstRegister() : NextVarRegister();
  422. this->envRegister = reg;
  423. return reg;
  424. }
  425. Js::RegSlot AssignThisRegister()
  426. {
  427. if (this->thisPointerRegister == Js::Constants::NoRegister)
  428. {
  429. this->thisPointerRegister = NextVarRegister();
  430. }
  431. return this->thisPointerRegister;
  432. }
  433. Js::RegSlot AssignSuperRegister()
  434. {
  435. if (this->superRegister == Js::Constants::NoRegister)
  436. {
  437. this->superRegister = NextVarRegister();
  438. }
  439. return this->superRegister;
  440. }
  441. Js::RegSlot AssignSuperCtorRegister()
  442. {
  443. if (this->superCtorRegister == Js::Constants::NoRegister)
  444. {
  445. this->superCtorRegister = NextVarRegister();
  446. }
  447. return this->superCtorRegister;
  448. }
  449. Js::RegSlot AssignNewTargetRegister()
  450. {
  451. if (this->newTargetRegister == Js::Constants::NoRegister)
  452. {
  453. this->newTargetRegister = NextVarRegister();
  454. }
  455. return this->newTargetRegister;
  456. }
  457. Js::RegSlot AssignNullConstRegister()
  458. {
  459. if (this->nullConstantRegister == Js::Constants::NoRegister)
  460. {
  461. this->nullConstantRegister = NextConstRegister();
  462. }
  463. return this->nullConstantRegister;
  464. }
  465. Js::RegSlot AssignUndefinedConstRegister()
  466. {
  467. if (this->undefinedConstantRegister == Js::Constants::NoRegister)
  468. {
  469. this->undefinedConstantRegister = NextConstRegister();
  470. }
  471. return this->undefinedConstantRegister;
  472. }
  473. Js::RegSlot AssignTrueConstRegister()
  474. {
  475. if (this->trueConstantRegister == Js::Constants::NoRegister)
  476. {
  477. this->trueConstantRegister = NextConstRegister();
  478. }
  479. return this->trueConstantRegister;
  480. }
  481. Js::RegSlot AssignFalseConstRegister()
  482. {
  483. if (this->falseConstantRegister == Js::Constants::NoRegister)
  484. {
  485. this->falseConstantRegister = NextConstRegister();
  486. }
  487. return this->falseConstantRegister;
  488. }
  489. Js::RegSlot AssignYieldRegister()
  490. {
  491. AssertMsg(this->yieldRegister == Js::Constants::NoRegister, "yield register should only be assigned once by FinalizeRegisters()");
  492. this->yieldRegister = NextVarRegister();
  493. return this->yieldRegister;
  494. }
  495. Js::RegSlot GetLocalScopeSlotsReg()
  496. {
  497. return this->localClosureReg;
  498. }
  499. Js::RegSlot GetLocalFrameDisplayReg()
  500. {
  501. return this->localClosureReg + 1;
  502. }
  503. Js::RegSlot InnerScopeToRegSlot(Scope *scope) const;
  504. Js::RegSlot FirstInnerScopeReg() const;
  505. void SetFirstInnerScopeReg(Js::RegSlot reg);
  506. void StartRecordingOutArgs(unsigned int argCount)
  507. {
  508. #if DBG
  509. outArgsDepth++;
  510. #endif
  511. // We should have checked for argCount overflow already
  512. Assert(argCount == (Js::ArgSlot)argCount);
  513. // Add one for the space to save the m_outParams pointer in InterpreterStackFrame::PushOut
  514. unsigned int outArgsCount = argCount + 1;
  515. outArgsCurrentExpr += (Js::ArgSlot)outArgsCount;
  516. // Check for overflow
  517. if ((Js::ArgSlot)outArgsCount != outArgsCount || outArgsCurrentExpr < outArgsCount)
  518. {
  519. Js::Throw::OutOfMemory();
  520. }
  521. outArgsMaxDepth = max(outArgsMaxDepth, outArgsCurrentExpr);
  522. }
  523. void EndRecordingOutArgs(Js::ArgSlot argCount)
  524. {
  525. AssertMsg(outArgsDepth > 0, "mismatched Start and End");
  526. Assert(outArgsCurrentExpr >= argCount);
  527. #if DBG
  528. outArgsDepth--;
  529. #endif
  530. // Add one to pop the space to save the m_outParams pointer
  531. outArgsCurrentExpr -= (argCount + 1);
  532. Assert(outArgsDepth != 0 || outArgsCurrentExpr == 0);
  533. }
  534. uint GetMaxForInLoopLevel() const { return this->maxForInLoopLevel; }
  535. uint AcquireForInLoopLevel()
  536. {
  537. uint forInLoopLevel = this->nextForInLoopLevel++;
  538. this->maxForInLoopLevel = max(this->maxForInLoopLevel, this->nextForInLoopLevel);
  539. return forInLoopLevel;
  540. }
  541. void ReleaseForInLoopLevel(uint forInLoopLevel)
  542. {
  543. Assert(this->nextForInLoopLevel == forInLoopLevel + 1);
  544. this->nextForInLoopLevel = forInLoopLevel;
  545. }
  546. Js::RegSlot AcquireLoc(ParseNode *pnode);
  547. Js::RegSlot AcquireTmpRegister();
  548. void ReleaseLoc(ParseNode *pnode);
  549. void ReleaseReference(ParseNode *pnode);
  550. void ReleaseLoad(ParseNode *pnode);
  551. void ReleaseTmpRegister(Js::RegSlot tmpReg);
  552. uint FindOrAddReferencedPropertyId(Js::PropertyId propertyId);
  553. uint FindOrAddRootObjectInlineCacheId(Js::PropertyId propertyId, bool isLoadMethod, bool isStore);
  554. uint FindOrAddInlineCacheId(Js::RegSlot instanceSlot, Js::PropertyId propertySlot, bool isLoadMethod, bool isStore)
  555. {
  556. Assert(instanceSlot != Js::Constants::NoRegister);
  557. Assert(propertySlot != Js::Constants::NoProperty);
  558. Assert(!isLoadMethod || !isStore);
  559. InlineCacheIdMap *properties;
  560. uint cacheId;
  561. if (isStore)
  562. {
  563. // ... = foo.toString;
  564. // foo.toString = ...;
  565. // We need a new cache here to ensure SetProperty() is called, which will set the side-effect bit
  566. // on the scriptContext.
  567. switch (propertySlot)
  568. {
  569. case Js::PropertyIds::valueOf:
  570. cacheId = this->NewInlineCache();
  571. valueOfStoreCacheIds.Prepend(alloc, cacheId);
  572. return cacheId;
  573. case Js::PropertyIds::toString:
  574. cacheId = this->NewInlineCache();
  575. toStringStoreCacheIds.Prepend(alloc, cacheId);
  576. return cacheId;
  577. };
  578. }
  579. if (!inlineCacheMap->TryGetValue(instanceSlot, &properties))
  580. {
  581. properties = Anew(alloc, InlineCacheIdMap, alloc, 17);
  582. inlineCacheMap->Add(instanceSlot, properties);
  583. }
  584. InlineCacheList* cacheList;
  585. if (!properties->TryGetValue(propertySlot, &cacheList))
  586. {
  587. cacheList = Anew(alloc, InlineCacheList, alloc);
  588. properties->Add(propertySlot, cacheList);
  589. }
  590. // If we share inline caches we should never have more than one entry in the list.
  591. Assert(Js::FunctionBody::ShouldShareInlineCaches() || cacheList->Count() <= 1);
  592. InlineCacheUnit cacheIdUnit;
  593. if (Js::FunctionBody::ShouldShareInlineCaches() && !cacheList->Empty())
  594. {
  595. cacheIdUnit = cacheList->Head();
  596. if (isLoadMethod)
  597. {
  598. if (cacheIdUnit.loadMethodCacheId == (uint)-1)
  599. {
  600. cacheIdUnit.loadMethodCacheId = this->NewInlineCache();
  601. }
  602. cacheId = cacheIdUnit.loadMethodCacheId;
  603. }
  604. else if (isStore)
  605. {
  606. if (cacheIdUnit.storeCacheId == (uint)-1)
  607. {
  608. cacheIdUnit.storeCacheId = this->NewInlineCache();
  609. }
  610. cacheId = cacheIdUnit.storeCacheId;
  611. }
  612. else
  613. {
  614. if (cacheIdUnit.loadCacheId == (uint)-1)
  615. {
  616. cacheIdUnit.loadCacheId = this->NewInlineCache();
  617. }
  618. cacheId = cacheIdUnit.loadCacheId;
  619. }
  620. cacheList->Head() = cacheIdUnit;
  621. }
  622. else
  623. {
  624. cacheId = this->NewInlineCache();
  625. if (Js::FunctionBody::ShouldShareInlineCaches())
  626. {
  627. if (isLoadMethod)
  628. {
  629. cacheIdUnit.loadCacheId = (uint)-1;
  630. cacheIdUnit.loadMethodCacheId = cacheId;
  631. cacheIdUnit.storeCacheId = (uint)-1;
  632. }
  633. else if (isStore)
  634. {
  635. cacheIdUnit.loadCacheId = (uint)-1;
  636. cacheIdUnit.loadMethodCacheId = (uint)-1;
  637. cacheIdUnit.storeCacheId = cacheId;
  638. }
  639. else
  640. {
  641. cacheIdUnit.loadCacheId = cacheId;
  642. cacheIdUnit.loadMethodCacheId = (uint)-1;
  643. cacheIdUnit.storeCacheId = (uint)-1;
  644. }
  645. }
  646. else
  647. {
  648. cacheIdUnit.cacheId = cacheId;
  649. }
  650. cacheList->Prepend(cacheIdUnit);
  651. }
  652. return cacheId;
  653. }
  654. Js::ProfileId FindOrAddSlotProfileId(Scope* scope, Js::PropertyId propertyId)
  655. {
  656. SlotKey key;
  657. key.scope = scope;
  658. key.slot = propertyId;
  659. Js::ProfileId profileId = Js::Constants::NoProfileId;
  660. if (!this->slotProfileIdMap.TryGetValue(key, &profileId))
  661. {
  662. Assert(this->byteCodeFunction->IsFunctionParsed());
  663. if (this->byteCodeFunction->GetFunctionBody()->AllocProfiledSlotId(&profileId))
  664. {
  665. this->slotProfileIdMap.Add(key, profileId);
  666. }
  667. }
  668. return profileId;
  669. }
  670. void EnsureThisScopeSlot();
  671. void EnsureSuperScopeSlot();
  672. void EnsureSuperCtorScopeSlot();
  673. void EnsureNewTargetScopeSlot();
  674. void SetIsThisLexicallyCaptured()
  675. {
  676. this->isThisLexicallyCaptured = true;
  677. }
  678. void SetIsSuperLexicallyCaptured()
  679. {
  680. this->isSuperLexicallyCaptured = true;
  681. }
  682. void SetIsSuperCtorLexicallyCaptured()
  683. {
  684. this->isSuperCtorLexicallyCaptured = true;
  685. }
  686. void SetIsNewTargetLexicallyCaptured()
  687. {
  688. this->isNewTargetLexicallyCaptured = true;
  689. }
  690. Scope * GetGlobalBlockScope() const;
  691. Scope * GetGlobalEvalBlockScope() const;
  692. FuncInfo *GetCurrentChildFunction() const
  693. {
  694. return this->currentChildFunction;
  695. }
  696. void SetCurrentChildFunction(FuncInfo *funcInfo)
  697. {
  698. this->currentChildFunction = funcInfo;
  699. }
  700. Scope *GetCurrentChildScope() const
  701. {
  702. return this->currentChildScope;
  703. }
  704. void SetCurrentChildScope(Scope *scope)
  705. {
  706. this->currentChildScope = scope;
  707. }
  708. SymbolTable *GetCapturedSyms() const { return capturedSyms; }
  709. void OnStartVisitFunction(ParseNode *pnodeFnc);
  710. void OnEndVisitFunction(ParseNode *pnodeFnc);
  711. void OnStartVisitScope(Scope *scope, bool *pisMergedScope);
  712. void OnEndVisitScope(Scope *scope, bool isMergedScope = false);
  713. void AddCapturedSym(Symbol *sym);
  714. CapturedSymMap *EnsureCapturedSymMap();
  715. #if DBG_DUMP
  716. void Dump();
  717. #endif
  718. };