FuncInfo.h 25 KB

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