FuncInfo.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  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. public:
  77. ArenaAllocator *alloc;
  78. // set in Bind/Assign pass
  79. Js::RegSlot varRegsCount; // number of registers used for non-constants
  80. Js::RegSlot constRegsCount; // number of registers used for constants
  81. Js::ArgSlot inArgsCount; // number of in args (including 'this')
  82. Js::RegSlot outArgsMaxDepth; // max depth of out args stack
  83. Js::RegSlot outArgsCurrentExpr; // max number of out args accumulated in the current nested expression
  84. uint innerScopeCount;
  85. uint currentInnerScopeIndex;
  86. #if DBG
  87. uint32 outArgsDepth; // number of calls nested in an expression
  88. #endif
  89. const char16 *name; // name of the function
  90. Js::RegSlot nullConstantRegister; // location, if any, of enregistered null constant
  91. Js::RegSlot undefinedConstantRegister; // location, if any, of enregistered undefined constant
  92. Js::RegSlot trueConstantRegister; // location, if any, of enregistered true constant
  93. Js::RegSlot falseConstantRegister; // location, if any, of enregistered false constant
  94. Js::RegSlot thisPointerRegister; // location, if any, of this pointer
  95. Js::RegSlot superRegister; // location, if any, of the super reference
  96. Js::RegSlot superCtorRegister; // location, if any, of the superCtor reference
  97. Js::RegSlot newTargetRegister; // location, if any, of the new.target reference
  98. private:
  99. Js::RegSlot envRegister; // location, if any, of the closure environment
  100. public:
  101. Js::RegSlot frameObjRegister; // location, if any, of the heap-allocated local frame
  102. Js::RegSlot frameSlotsRegister; // location, if any, of the heap-allocated local frame
  103. Js::RegSlot paramSlotsRegister; // location, if any, of the heap allocated local frame for param scope
  104. Js::RegSlot frameDisplayRegister; // location, if any, of the display of nested frames
  105. Js::RegSlot funcObjRegister;
  106. Js::RegSlot localClosureReg;
  107. Js::RegSlot yieldRegister;
  108. Js::RegSlot firstTmpReg;
  109. Js::RegSlot curTmpReg;
  110. int sameNameArgsPlaceHolderSlotCount; // count of place holder slots for same name args
  111. int localPropIdOffset;
  112. Js::RegSlot firstThunkArgReg;
  113. short thunkArgCount;
  114. short staticFuncId;
  115. uint callsEval : 1;
  116. uint childCallsEval : 1;
  117. uint hasArguments : 1;
  118. uint hasHeapArguments : 1;
  119. uint isTopLevelEventHandler : 1;
  120. uint hasLocalInClosure : 1;
  121. uint hasClosureReference : 1;
  122. uint hasGlobalReference : 1;
  123. uint hasCachedScope : 1;
  124. uint funcExprNameReference : 1;
  125. uint applyEnclosesArgs : 1;
  126. uint escapes : 1;
  127. uint hasDeferredChild : 1; // switch for DeferNested to persist outer scopes
  128. uint childHasWith : 1; // deferNested needs to know if child has with
  129. uint hasLoop : 1;
  130. uint hasEscapedUseNestedFunc : 1;
  131. uint needEnvRegister : 1;
  132. uint hasCapturedThis : 1;
  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, PowerOf2SizePolicy, Js::StringTemplateCallsiteObjectComparer> StringTemplateCallsiteRegisterMap;
  140. StringTemplateCallsiteRegisterMap stringTemplateCallsiteRegisterMap; // maps string template callsite constant to register
  141. Scope *paramScope; // top level scope for parameter default values
  142. Scope *bodyScope; // top level scope of the function body
  143. Scope *funcExprScope;
  144. ParseNode *root; // top-level AST for function
  145. Js::ParseableFunctionInfo* byteCodeFunction; // reference to generated bytecode function (could be defer parsed or actually parsed)
  146. SList<ParseNode*> targetStatements; // statements that are targets of jumps (break or continue)
  147. Js::ByteCodeLabel singleExit;
  148. typedef SList<InlineCacheUnit> InlineCacheList;
  149. typedef JsUtil::BaseDictionary<Js::PropertyId, InlineCacheList*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheIdMap;
  150. typedef JsUtil::BaseDictionary<Js::RegSlot, InlineCacheIdMap*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheMap;
  151. typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> RootObjectInlineCacheIdMap;
  152. typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> ReferencedPropertyIdMap;
  153. RootObjectInlineCacheIdMap * rootObjectLoadInlineCacheMap;
  154. RootObjectInlineCacheIdMap * rootObjectLoadMethodInlineCacheMap;
  155. RootObjectInlineCacheIdMap * rootObjectStoreInlineCacheMap;
  156. InlineCacheMap * inlineCacheMap;
  157. ReferencedPropertyIdMap * referencedPropertyIdToMapIndex;
  158. SListBase<uint> valueOfStoreCacheIds;
  159. SListBase<uint> toStringStoreCacheIds;
  160. typedef JsUtil::BaseDictionary<SlotKey, Js::ProfileId, ArenaAllocator, PowerOf2SizePolicy, SlotKeyComparer> SlotProfileIdMap;
  161. SlotProfileIdMap slotProfileIdMap;
  162. Js::PropertyId thisScopeSlot;
  163. Js::PropertyId superScopeSlot;
  164. Js::PropertyId superCtorScopeSlot;
  165. Js::PropertyId newTargetScopeSlot;
  166. bool isThisLexicallyCaptured;
  167. bool isSuperLexicallyCaptured;
  168. bool isSuperCtorLexicallyCaptured;
  169. bool isNewTargetLexicallyCaptured;
  170. Symbol *argumentsSymbol;
  171. JsUtil::List<Js::RegSlot, ArenaAllocator> nonUserNonTempRegistersToInitialize;
  172. // constRegsCount is set to 2 because R0 is the return register, and R1 is the root object.
  173. FuncInfo(
  174. const char16 *name,
  175. ArenaAllocator *alloc,
  176. Scope *paramScope,
  177. Scope *bodyScope,
  178. ParseNode *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(ulong flags) const {
  234. return IsGlobalFunction() && !(flags & fscrGlobalCode);
  235. }
  236. Scope *GetBodyScope() const {
  237. return bodyScope;
  238. }
  239. Scope *GetParamScope() const {
  240. return paramScope;
  241. }
  242. Scope *GetTopLevelScope() const {
  243. // Top level scope will be the same for knopProg and knopFncDecl.
  244. return paramScope;
  245. }
  246. Scope* GetFuncExprScope() const {
  247. return funcExprScope;
  248. }
  249. void SetFuncExprScope(Scope* funcExprScope) {
  250. this->funcExprScope = funcExprScope;
  251. }
  252. Symbol *GetArgumentsSymbol() const
  253. {
  254. return argumentsSymbol;
  255. }
  256. void SetArgumentsSymbol(Symbol *sym)
  257. {
  258. Assert(argumentsSymbol == nullptr || argumentsSymbol == sym);
  259. argumentsSymbol = sym;
  260. }
  261. bool GetCallsEval() const {
  262. return callsEval;
  263. }
  264. void SetCallsEval(bool does) {
  265. callsEval = does;
  266. }
  267. bool GetHasArguments() const {
  268. return hasArguments;
  269. }
  270. void SetHasArguments(bool has) {
  271. hasArguments = has;
  272. }
  273. bool GetHasHeapArguments() const
  274. {
  275. return hasHeapArguments;
  276. }
  277. void SetHasHeapArguments(bool has, bool optArgInBackend = false)
  278. {
  279. hasHeapArguments = has;
  280. byteCodeFunction->SetDoBackendArgumentsOptimization(optArgInBackend);
  281. }
  282. bool GetIsTopLevelEventHandler() const {
  283. return isTopLevelEventHandler;
  284. }
  285. void SetIsTopLevelEventHandler(bool is) {
  286. isTopLevelEventHandler = is;
  287. }
  288. bool GetChildCallsEval() const {
  289. return childCallsEval;
  290. }
  291. void SetChildCallsEval(bool does) {
  292. childCallsEval = does;
  293. }
  294. bool GetHasLocalInClosure() const {
  295. return hasLocalInClosure;
  296. }
  297. void SetHasLocalInClosure(bool has) {
  298. hasLocalInClosure = has;
  299. }
  300. bool GetHasClosureReference() const {
  301. return hasClosureReference;
  302. }
  303. void SetHasCachedScope(bool has) {
  304. hasCachedScope = has;
  305. }
  306. bool GetHasCachedScope() const {
  307. return hasCachedScope;
  308. }
  309. void SetFuncExprNameReference(bool has) {
  310. funcExprNameReference = has;
  311. }
  312. bool GetFuncExprNameReference() const {
  313. return funcExprNameReference;
  314. }
  315. void SetHasClosureReference(bool has) {
  316. hasClosureReference = has;
  317. }
  318. bool GetHasGlobalRef() const {
  319. return hasGlobalReference;
  320. }
  321. void SetHasGlobalRef(bool has) {
  322. hasGlobalReference = has;
  323. }
  324. bool GetIsStrictMode() const {
  325. return this->byteCodeFunction->GetIsStrictMode();
  326. }
  327. bool Escapes() const {
  328. return escapes;
  329. }
  330. void SetEscapes(bool does) {
  331. escapes = does;
  332. }
  333. bool HasMaybeEscapedNestedFunc() const {
  334. return hasEscapedUseNestedFunc;
  335. }
  336. void SetHasMaybeEscapedNestedFunc(DebugOnly(char16 const * reason));
  337. bool IsDeferred() const;
  338. bool IsRestored()
  339. {
  340. // FuncInfo are from RestoredScopeInfo
  341. return root == nullptr;
  342. }
  343. bool HasDeferredChild() const {
  344. return hasDeferredChild;
  345. }
  346. void SetHasDeferredChild() {
  347. hasDeferredChild = true;
  348. }
  349. Js::FunctionBody* GetParsedFunctionBody() const
  350. {
  351. AssertMsg(this->byteCodeFunction->IsFunctionParsed(), "Function must be parsed in order to call this method");
  352. Assert(!IsDeferred());
  353. return this->byteCodeFunction->GetFunctionBody();
  354. }
  355. bool ChildHasWith() const {
  356. return childHasWith;
  357. }
  358. void SetChildHasWith() {
  359. childHasWith = true;
  360. }
  361. bool HasCapturedThis() const {
  362. return hasCapturedThis;
  363. }
  364. void SetHasCapturedThis() {
  365. hasCapturedThis = true;
  366. }
  367. BOOL HasSuperReference() const;
  368. BOOL HasDirectSuper() const;
  369. BOOL IsClassMember() const;
  370. BOOL IsLambda() const;
  371. BOOL IsClassConstructor() const;
  372. BOOL IsBaseClassConstructor() const;
  373. void RemoveTargetStmt(ParseNode* pnodeStmt) {
  374. targetStatements.Remove(pnodeStmt);
  375. }
  376. void AddTargetStmt(ParseNode *pnodeStmt) {
  377. targetStatements.Prepend(pnodeStmt);
  378. }
  379. Js::RegSlot LookupDouble(double d) {
  380. return doubleConstantToRegister.Lookup(d,Js::Constants::NoRegister);
  381. }
  382. bool TryGetDoubleLoc(double d, Js::RegSlot *loc) {
  383. Js::RegSlot ret=LookupDouble(d);
  384. *loc=ret;
  385. return(ret!=Js::Constants::NoRegister);
  386. }
  387. void AddDoubleConstant(double d, Js::RegSlot location) {
  388. doubleConstantToRegister.Item(d,location);
  389. }
  390. bool NeedEnvRegister() const { return this->needEnvRegister; }
  391. void SetNeedEnvRegister() { this->needEnvRegister = true; };
  392. Js::RegSlot GetEnvRegister() const
  393. {
  394. Assert(this->envRegister != Js::Constants::NoRegister);
  395. return this->envRegister;
  396. }
  397. Js::RegSlot AssignEnvRegister(bool constReg)
  398. {
  399. Assert(needEnvRegister);
  400. Assert(this->envRegister == Js::Constants::NoRegister);
  401. Js::RegSlot reg = constReg? NextConstRegister() : NextVarRegister();
  402. this->envRegister = reg;
  403. return reg;
  404. }
  405. Js::RegSlot AssignThisRegister()
  406. {
  407. if (this->thisPointerRegister == Js::Constants::NoRegister)
  408. {
  409. this->thisPointerRegister = NextVarRegister();
  410. }
  411. return this->thisPointerRegister;
  412. }
  413. Js::RegSlot AssignSuperRegister()
  414. {
  415. if (this->superRegister == Js::Constants::NoRegister)
  416. {
  417. this->superRegister = NextVarRegister();
  418. }
  419. return this->superRegister;
  420. }
  421. Js::RegSlot AssignSuperCtorRegister()
  422. {
  423. if (this->superCtorRegister == Js::Constants::NoRegister)
  424. {
  425. this->superCtorRegister = NextVarRegister();
  426. }
  427. return this->superCtorRegister;
  428. }
  429. Js::RegSlot AssignNewTargetRegister()
  430. {
  431. if (this->newTargetRegister == Js::Constants::NoRegister)
  432. {
  433. this->newTargetRegister = NextVarRegister();
  434. }
  435. return this->newTargetRegister;
  436. }
  437. Js::RegSlot AssignNullConstRegister()
  438. {
  439. if (this->nullConstantRegister == Js::Constants::NoRegister)
  440. {
  441. this->nullConstantRegister = NextConstRegister();
  442. }
  443. return this->nullConstantRegister;
  444. }
  445. Js::RegSlot AssignUndefinedConstRegister()
  446. {
  447. if (this->undefinedConstantRegister == Js::Constants::NoRegister)
  448. {
  449. this->undefinedConstantRegister = NextConstRegister();
  450. }
  451. return this->undefinedConstantRegister;
  452. }
  453. Js::RegSlot AssignTrueConstRegister()
  454. {
  455. if (this->trueConstantRegister == Js::Constants::NoRegister)
  456. {
  457. this->trueConstantRegister = NextConstRegister();
  458. }
  459. return this->trueConstantRegister;
  460. }
  461. Js::RegSlot AssignFalseConstRegister()
  462. {
  463. if (this->falseConstantRegister == Js::Constants::NoRegister)
  464. {
  465. this->falseConstantRegister = NextConstRegister();
  466. }
  467. return this->falseConstantRegister;
  468. }
  469. Js::RegSlot AssignYieldRegister()
  470. {
  471. AssertMsg(this->yieldRegister == Js::Constants::NoRegister, "yield register should only be assigned once by FinalizeRegisters()");
  472. this->yieldRegister = NextVarRegister();
  473. return this->yieldRegister;
  474. }
  475. Js::RegSlot GetLocalScopeSlotsReg()
  476. {
  477. return this->localClosureReg;
  478. }
  479. Js::RegSlot GetLocalFrameDisplayReg()
  480. {
  481. return this->localClosureReg + 1;
  482. }
  483. Js::RegSlot InnerScopeToRegSlot(Scope *scope) const;
  484. Js::RegSlot FirstInnerScopeReg() const;
  485. void SetFirstInnerScopeReg(Js::RegSlot reg);
  486. void StartRecordingOutArgs(unsigned int argCount)
  487. {
  488. #if DBG
  489. outArgsDepth++;
  490. #endif
  491. // We should have checked for argCount overflow already
  492. Assert(argCount == (Js::ArgSlot)argCount);
  493. // Add one for the space to save the m_outParams pointer in InterpreterStackFrame::PushOut
  494. unsigned int outArgsCount = argCount + 1;
  495. outArgsCurrentExpr += (Js::ArgSlot)outArgsCount;
  496. // Check for overflow
  497. if ((Js::ArgSlot)outArgsCount != outArgsCount || outArgsCurrentExpr < outArgsCount)
  498. {
  499. Js::Throw::OutOfMemory();
  500. }
  501. outArgsMaxDepth = max(outArgsMaxDepth, outArgsCurrentExpr);
  502. }
  503. void EndRecordingOutArgs(Js::ArgSlot argCount)
  504. {
  505. AssertMsg(outArgsDepth > 0, "mismatched Start and End");
  506. Assert(outArgsCurrentExpr >= argCount);
  507. #if DBG
  508. outArgsDepth--;
  509. #endif
  510. // Add one to pop the space to save the m_outParams pointer
  511. outArgsCurrentExpr -= (argCount + 1);
  512. Assert(outArgsDepth != 0 || outArgsCurrentExpr == 0);
  513. }
  514. Js::RegSlot AcquireLoc(ParseNode *pnode);
  515. Js::RegSlot AcquireTmpRegister();
  516. void ReleaseLoc(ParseNode *pnode);
  517. void ReleaseReference(ParseNode *pnode);
  518. void ReleaseLoad(ParseNode *pnode);
  519. void ReleaseTmpRegister(Js::RegSlot tmpReg);
  520. uint FindOrAddReferencedPropertyId(Js::PropertyId propertyId);
  521. uint FindOrAddRootObjectInlineCacheId(Js::PropertyId propertyId, bool isLoadMethod, bool isStore);
  522. uint FindOrAddInlineCacheId(Js::RegSlot instanceSlot, Js::PropertyId propertySlot, bool isLoadMethod, bool isStore)
  523. {
  524. Assert(instanceSlot != Js::Constants::NoRegister);
  525. Assert(propertySlot != Js::Constants::NoProperty);
  526. Assert(!isLoadMethod || !isStore);
  527. InlineCacheIdMap *properties;
  528. uint cacheId;
  529. if (isStore)
  530. {
  531. // ... = foo.toString;
  532. // foo.toString = ...;
  533. // We need a new cache here to ensure SetProperty() is called, which will set the side-effect bit
  534. // on the scriptContext.
  535. switch (propertySlot)
  536. {
  537. case Js::PropertyIds::valueOf:
  538. cacheId = this->NewInlineCache();
  539. valueOfStoreCacheIds.Prepend(alloc, cacheId);
  540. return cacheId;
  541. case Js::PropertyIds::toString:
  542. cacheId = this->NewInlineCache();
  543. toStringStoreCacheIds.Prepend(alloc, cacheId);
  544. return cacheId;
  545. };
  546. }
  547. if (!inlineCacheMap->TryGetValue(instanceSlot, &properties))
  548. {
  549. properties = Anew(alloc, InlineCacheIdMap, alloc, 17);
  550. inlineCacheMap->Add(instanceSlot, properties);
  551. }
  552. InlineCacheList* cacheList;
  553. if (!properties->TryGetValue(propertySlot, &cacheList))
  554. {
  555. cacheList = Anew(alloc, InlineCacheList, alloc);
  556. properties->Add(propertySlot, cacheList);
  557. }
  558. // If we share inline caches we should never have more than one entry in the list.
  559. Assert(Js::FunctionBody::ShouldShareInlineCaches() || cacheList->Count() <= 1);
  560. InlineCacheUnit cacheIdUnit;
  561. if (Js::FunctionBody::ShouldShareInlineCaches() && !cacheList->Empty())
  562. {
  563. cacheIdUnit = cacheList->Head();
  564. if (isLoadMethod)
  565. {
  566. if (cacheIdUnit.loadMethodCacheId == (uint)-1)
  567. {
  568. cacheIdUnit.loadMethodCacheId = this->NewInlineCache();
  569. }
  570. cacheId = cacheIdUnit.loadMethodCacheId;
  571. }
  572. else if (isStore)
  573. {
  574. if (cacheIdUnit.storeCacheId == (uint)-1)
  575. {
  576. cacheIdUnit.storeCacheId = this->NewInlineCache();
  577. }
  578. cacheId = cacheIdUnit.storeCacheId;
  579. }
  580. else
  581. {
  582. if (cacheIdUnit.loadCacheId == (uint)-1)
  583. {
  584. cacheIdUnit.loadCacheId = this->NewInlineCache();
  585. }
  586. cacheId = cacheIdUnit.loadCacheId;
  587. }
  588. cacheList->Head() = cacheIdUnit;
  589. }
  590. else
  591. {
  592. cacheId = this->NewInlineCache();
  593. if (Js::FunctionBody::ShouldShareInlineCaches())
  594. {
  595. if (isLoadMethod)
  596. {
  597. cacheIdUnit.loadCacheId = (uint)-1;
  598. cacheIdUnit.loadMethodCacheId = cacheId;
  599. cacheIdUnit.storeCacheId = (uint)-1;
  600. }
  601. else if (isStore)
  602. {
  603. cacheIdUnit.loadCacheId = (uint)-1;
  604. cacheIdUnit.loadMethodCacheId = (uint)-1;
  605. cacheIdUnit.storeCacheId = cacheId;
  606. }
  607. else
  608. {
  609. cacheIdUnit.loadCacheId = cacheId;
  610. cacheIdUnit.loadMethodCacheId = (uint)-1;
  611. cacheIdUnit.storeCacheId = (uint)-1;
  612. }
  613. }
  614. else
  615. {
  616. cacheIdUnit.cacheId = cacheId;
  617. }
  618. cacheList->Prepend(cacheIdUnit);
  619. }
  620. return cacheId;
  621. }
  622. Js::ProfileId FindOrAddSlotProfileId(Scope* scope, Js::PropertyId propertyId)
  623. {
  624. SlotKey key;
  625. key.scope = scope;
  626. key.slot = propertyId;
  627. Js::ProfileId profileId = Js::Constants::NoProfileId;
  628. if (!this->slotProfileIdMap.TryGetValue(key, &profileId))
  629. {
  630. Assert(this->byteCodeFunction->IsFunctionParsed());
  631. if (this->byteCodeFunction->GetFunctionBody()->AllocProfiledSlotId(&profileId))
  632. {
  633. this->slotProfileIdMap.Add(key, profileId);
  634. }
  635. }
  636. return profileId;
  637. }
  638. void EnsureThisScopeSlot(Scope* scope);
  639. void EnsureSuperScopeSlot(Scope* scope);
  640. void EnsureSuperCtorScopeSlot(Scope* scope);
  641. void EnsureNewTargetScopeSlot(Scope* scope);
  642. void SetIsThisLexicallyCaptured()
  643. {
  644. this->isThisLexicallyCaptured = true;
  645. }
  646. void SetIsSuperLexicallyCaptured()
  647. {
  648. this->isSuperLexicallyCaptured = true;
  649. }
  650. void SetIsSuperCtorLexicallyCaptured()
  651. {
  652. this->isSuperCtorLexicallyCaptured = true;
  653. }
  654. void SetIsNewTargetLexicallyCaptured()
  655. {
  656. this->isNewTargetLexicallyCaptured = true;
  657. }
  658. Scope * GetGlobalBlockScope() const;
  659. Scope * GetGlobalEvalBlockScope() const;
  660. FuncInfo *GetCurrentChildFunction() const
  661. {
  662. return this->currentChildFunction;
  663. }
  664. void SetCurrentChildFunction(FuncInfo *funcInfo)
  665. {
  666. this->currentChildFunction = funcInfo;
  667. }
  668. Scope *GetCurrentChildScope() const
  669. {
  670. return this->currentChildScope;
  671. }
  672. void SetCurrentChildScope(Scope *scope)
  673. {
  674. this->currentChildScope = scope;
  675. }
  676. SymbolTable *GetCapturedSyms() const { return capturedSyms; }
  677. void OnStartVisitFunction(ParseNode *pnodeFnc);
  678. void OnEndVisitFunction(ParseNode *pnodeFnc);
  679. void OnStartVisitScope(Scope *scope, bool *pisMergedScope);
  680. void OnEndVisitScope(Scope *scope, bool isMergedScope = false);
  681. void AddCapturedSym(Symbol *sym);
  682. CapturedSymMap *EnsureCapturedSymMap();
  683. #if DBG_DUMP
  684. void Dump();
  685. #endif
  686. };