FuncInfo.h 26 KB

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