FuncInfo.h 25 KB

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