FuncInfo.h 25 KB

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