FuncInfo.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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. #include "RuntimeByteCodePch.h"
  6. FuncInfo::FuncInfo(
  7. const char16 *name,
  8. ArenaAllocator *alloc,
  9. Scope *paramScope,
  10. Scope *bodyScope,
  11. ParseNode *pnode,
  12. Js::ParseableFunctionInfo* byteCodeFunction)
  13. : alloc(alloc),
  14. varRegsCount(0),
  15. constRegsCount(InitialConstRegsCount),
  16. inArgsCount(0),
  17. innerScopeCount(0),
  18. currentInnerScopeIndex((uint)-1),
  19. firstTmpReg(Js::Constants::NoRegister),
  20. curTmpReg(Js::Constants::NoRegister),
  21. outArgsMaxDepth(0),
  22. outArgsCurrentExpr(0),
  23. #if DBG
  24. outArgsDepth(0),
  25. #endif
  26. name(name),
  27. nullConstantRegister(Js::Constants::NoRegister),
  28. undefinedConstantRegister(Js::Constants::NoRegister),
  29. trueConstantRegister(Js::Constants::NoRegister),
  30. falseConstantRegister(Js::Constants::NoRegister),
  31. thisPointerRegister(Js::Constants::NoRegister),
  32. superRegister(Js::Constants::NoRegister),
  33. superCtorRegister(Js::Constants::NoRegister),
  34. newTargetRegister(Js::Constants::NoRegister),
  35. envRegister(Js::Constants::NoRegister),
  36. frameObjRegister(Js::Constants::NoRegister),
  37. frameSlotsRegister(Js::Constants::NoRegister),
  38. paramSlotsRegister(Js::Constants::NoRegister),
  39. frameDisplayRegister(Js::Constants::NoRegister),
  40. funcObjRegister(Js::Constants::NoRegister),
  41. localClosureReg(Js::Constants::NoRegister),
  42. yieldRegister(Js::Constants::NoRegister),
  43. paramScope(paramScope),
  44. bodyScope(bodyScope),
  45. funcExprScope(nullptr),
  46. root(pnode),
  47. capturedSyms(nullptr),
  48. capturedSymMap(nullptr),
  49. currentChildFunction(nullptr),
  50. currentChildScope(nullptr),
  51. callsEval(false),
  52. childCallsEval(false),
  53. hasArguments(false),
  54. hasHeapArguments(false),
  55. isTopLevelEventHandler(false),
  56. hasLocalInClosure(false),
  57. hasClosureReference(false),
  58. hasGlobalReference(false),
  59. hasCachedScope(false),
  60. funcExprNameReference(false),
  61. applyEnclosesArgs(false),
  62. escapes(false),
  63. hasDeferredChild(false),
  64. hasRedeferrableChild(false),
  65. childHasWith(false),
  66. hasLoop(false),
  67. hasEscapedUseNestedFunc(false),
  68. needEnvRegister(false),
  69. hasCapturedThis(false),
  70. #if DBG
  71. isReused(false),
  72. #endif
  73. staticFuncId(-1),
  74. inlineCacheMap(nullptr),
  75. slotProfileIdMap(alloc),
  76. argsPlaceHolderSlotCount(0),
  77. thisScopeSlot(Js::Constants::NoProperty),
  78. innerThisScopeSlot(Js::Constants::NoProperty),
  79. superScopeSlot(Js::Constants::NoProperty),
  80. innerSuperScopeSlot(Js::Constants::NoProperty),
  81. superCtorScopeSlot(Js::Constants::NoProperty),
  82. innerSuperCtorScopeSlot(Js::Constants::NoProperty),
  83. newTargetScopeSlot(Js::Constants::NoProperty),
  84. innerNewTargetScopeSlot(Js::Constants::NoProperty),
  85. isThisLexicallyCaptured(false),
  86. isSuperLexicallyCaptured(false),
  87. isSuperCtorLexicallyCaptured(false),
  88. isNewTargetLexicallyCaptured(false),
  89. inlineCacheCount(0),
  90. rootObjectLoadInlineCacheCount(0),
  91. rootObjectLoadMethodInlineCacheCount(0),
  92. rootObjectStoreInlineCacheCount(0),
  93. isInstInlineCacheCount(0),
  94. referencedPropertyIdCount(0),
  95. argumentsSymbol(nullptr),
  96. innerArgumentsSymbol(nullptr),
  97. nonUserNonTempRegistersToInitialize(alloc),
  98. constantToRegister(alloc, 17),
  99. stringToRegister(alloc, 17),
  100. doubleConstantToRegister(alloc, 17),
  101. stringTemplateCallsiteRegisterMap(alloc, 17),
  102. targetStatements(alloc),
  103. nextForInLoopLevel(0),
  104. maxForInLoopLevel(0)
  105. {
  106. this->byteCodeFunction = byteCodeFunction;
  107. bodyScope->SetFunc(this);
  108. if (paramScope != nullptr)
  109. {
  110. paramScope->SetFunc(this);
  111. }
  112. if (pnode && pnode->sxFnc.NestedFuncEscapes())
  113. {
  114. this->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("Child")));
  115. }
  116. }
  117. bool FuncInfo::IsGlobalFunction() const
  118. {
  119. return root && root->nop == knopProg;
  120. }
  121. bool FuncInfo::IsDeferred() const
  122. {
  123. return root && root->sxFnc.pnodeBody == nullptr;
  124. }
  125. bool FuncInfo::IsRedeferrable() const
  126. {
  127. return byteCodeFunction && byteCodeFunction->CanBeDeferred();
  128. }
  129. BOOL FuncInfo::HasSuperReference() const
  130. {
  131. return root->sxFnc.HasSuperReference();
  132. }
  133. BOOL FuncInfo::HasDirectSuper() const
  134. {
  135. return root->sxFnc.HasDirectSuper();
  136. }
  137. BOOL FuncInfo::IsClassMember() const
  138. {
  139. return root->sxFnc.IsClassMember();
  140. }
  141. BOOL FuncInfo::IsLambda() const
  142. {
  143. return root->sxFnc.IsLambda();
  144. }
  145. BOOL FuncInfo::IsClassConstructor() const
  146. {
  147. return root->sxFnc.IsClassConstructor();
  148. }
  149. BOOL FuncInfo::IsBaseClassConstructor() const
  150. {
  151. return root->sxFnc.IsBaseClassConstructor();
  152. }
  153. void FuncInfo::EnsureThisScopeSlot()
  154. {
  155. if (this->thisScopeSlot == Js::Constants::NoProperty)
  156. {
  157. // In case of split scope param and body has separate closures. So we have to use different scope slots for them.
  158. bool isSplitScope = this->paramScope && !this->paramScope->GetCanMergeWithBodyScope();
  159. Scope* scope = isSplitScope ? this->paramScope : this->bodyScope;
  160. Scope* currentScope = scope->IsGlobalEvalBlockScope() ? this->GetGlobalEvalBlockScope() : scope;
  161. this->thisScopeSlot = currentScope->AddScopeSlot();
  162. if (isSplitScope)
  163. {
  164. this->innerThisScopeSlot = this->bodyScope->AddScopeSlot();
  165. }
  166. }
  167. }
  168. void FuncInfo::EnsureSuperScopeSlot()
  169. {
  170. if (this->superScopeSlot == Js::Constants::NoProperty)
  171. {
  172. // In case of split scope param and body has separate closures. So we have to use different scope slots for them.
  173. bool isSplitScope = this->paramScope && !this->paramScope->GetCanMergeWithBodyScope();
  174. Scope* scope = isSplitScope ? this->paramScope : this->bodyScope;
  175. this->superScopeSlot = scope->AddScopeSlot();
  176. if (isSplitScope)
  177. {
  178. this->innerSuperScopeSlot = this->bodyScope->AddScopeSlot();
  179. }
  180. }
  181. }
  182. void FuncInfo::EnsureSuperCtorScopeSlot()
  183. {
  184. if (this->superCtorScopeSlot == Js::Constants::NoProperty)
  185. {
  186. // In case of split scope param and body has separate closures. So we have to use different scope slots for them.
  187. bool isSplitScope = this->paramScope && !this->paramScope->GetCanMergeWithBodyScope();
  188. Scope* scope = isSplitScope ? this->paramScope : this->bodyScope;
  189. this->superCtorScopeSlot = scope->AddScopeSlot();
  190. if (isSplitScope)
  191. {
  192. this->innerSuperCtorScopeSlot = this->bodyScope->AddScopeSlot();
  193. }
  194. }
  195. }
  196. void FuncInfo::EnsureNewTargetScopeSlot()
  197. {
  198. if (this->newTargetScopeSlot == Js::Constants::NoProperty)
  199. {
  200. // In case of split scope param and body has separate closures. So we have to use different scope slots for them.
  201. bool isSplitScope = this->paramScope && !this->paramScope->GetCanMergeWithBodyScope();
  202. Scope* scope = isSplitScope ? this->paramScope : this->bodyScope;
  203. this->newTargetScopeSlot = scope->AddScopeSlot();
  204. if (isSplitScope)
  205. {
  206. this->innerNewTargetScopeSlot = this->bodyScope->AddScopeSlot();
  207. }
  208. }
  209. }
  210. void FuncInfo::UseInnerSpecialScopeSlots()
  211. {
  212. Assert(this->paramScope != nullptr && !this->paramScope->GetCanMergeWithBodyScope());
  213. Js::PropertyId temp = Js::Constants::NoProperty;
  214. if (this->thisScopeSlot != Js::Constants::NoProperty)
  215. {
  216. Assert(this->innerThisScopeSlot != Js::Constants::NoProperty);
  217. temp = this->thisScopeSlot;
  218. this->thisScopeSlot = this->innerThisScopeSlot;
  219. this->innerThisScopeSlot = temp;
  220. }
  221. if (this->superScopeSlot != Js::Constants::NoProperty)
  222. {
  223. Assert(this->innerSuperScopeSlot != Js::Constants::NoProperty);
  224. temp = this->superScopeSlot;
  225. this->superScopeSlot = this->innerSuperScopeSlot;
  226. this->innerSuperScopeSlot = temp;
  227. }
  228. if (this->superCtorScopeSlot != Js::Constants::NoProperty)
  229. {
  230. Assert(this->innerSuperCtorScopeSlot != Js::Constants::NoProperty);
  231. temp = this->superCtorScopeSlot;
  232. this->superCtorScopeSlot = this->innerSuperCtorScopeSlot;
  233. this->innerSuperCtorScopeSlot = temp;
  234. }
  235. if (this->newTargetScopeSlot != Js::Constants::NoProperty)
  236. {
  237. Assert(this->innerNewTargetScopeSlot != Js::Constants::NoProperty);
  238. temp = this->newTargetScopeSlot;
  239. this->newTargetScopeSlot = this->innerNewTargetScopeSlot;
  240. this->innerNewTargetScopeSlot = temp;
  241. }
  242. }
  243. Scope *
  244. FuncInfo::GetGlobalBlockScope() const
  245. {
  246. Assert(this->IsGlobalFunction());
  247. Scope * scope = this->root->sxFnc.pnodeScopes->sxBlock.scope;
  248. Assert(scope == nullptr || scope == this->GetBodyScope() || scope->GetEnclosingScope() == this->GetBodyScope());
  249. return scope;
  250. }
  251. Scope * FuncInfo::GetGlobalEvalBlockScope() const
  252. {
  253. Scope * globalEvalBlockScope = this->GetGlobalBlockScope();
  254. Assert(globalEvalBlockScope->GetEnclosingScope() == this->GetBodyScope());
  255. Assert(globalEvalBlockScope->GetScopeType() == ScopeType_GlobalEvalBlock);
  256. return globalEvalBlockScope;
  257. }
  258. uint FuncInfo::FindOrAddReferencedPropertyId(Js::PropertyId propertyId)
  259. {
  260. Assert(propertyId != Js::Constants::NoProperty);
  261. Assert(referencedPropertyIdToMapIndex != nullptr);
  262. if (propertyId < TotalNumberOfBuiltInProperties)
  263. {
  264. return propertyId;
  265. }
  266. uint index;
  267. if (!referencedPropertyIdToMapIndex->TryGetValue(propertyId, &index))
  268. {
  269. index = this->NewReferencedPropertyId();
  270. referencedPropertyIdToMapIndex->Add(propertyId, index);
  271. }
  272. return index + TotalNumberOfBuiltInProperties;
  273. }
  274. uint FuncInfo::FindOrAddRootObjectInlineCacheId(Js::PropertyId propertyId, bool isLoadMethod, bool isStore)
  275. {
  276. Assert(propertyId != Js::Constants::NoProperty);
  277. Assert(!isLoadMethod || !isStore);
  278. uint cacheId;
  279. RootObjectInlineCacheIdMap * idMap = isStore ? rootObjectStoreInlineCacheMap : isLoadMethod ? rootObjectLoadMethodInlineCacheMap : rootObjectLoadInlineCacheMap;
  280. if (!idMap->TryGetValue(propertyId, &cacheId))
  281. {
  282. cacheId = isStore ? this->NewRootObjectStoreInlineCache() : isLoadMethod ? this->NewRootObjectLoadMethodInlineCache() : this->NewRootObjectLoadInlineCache();
  283. idMap->Add(propertyId, cacheId);
  284. }
  285. return cacheId;
  286. }
  287. #if DBG_DUMP
  288. void FuncInfo::Dump()
  289. {
  290. Output::Print(_u("FuncInfo: CallsEval:%s ChildCallsEval:%s HasArguments:%s HasHeapArguments:%s\n"),
  291. IsTrueOrFalse(this->GetCallsEval()),
  292. IsTrueOrFalse(this->GetChildCallsEval()),
  293. IsTrueOrFalse(this->GetHasArguments()),
  294. IsTrueOrFalse(this->GetHasHeapArguments()));
  295. }
  296. #endif
  297. Js::RegSlot FuncInfo::AcquireLoc(ParseNode *pnode)
  298. {
  299. // Assign a new temp pseudo-register to this expression.
  300. if (pnode->location == Js::Constants::NoRegister)
  301. {
  302. pnode->location = this->AcquireTmpRegister();
  303. }
  304. return pnode->location;
  305. }
  306. Js::RegSlot FuncInfo::AcquireTmpRegister()
  307. {
  308. Assert(this->firstTmpReg != Js::Constants::NoRegister);
  309. // Allocate a new temp pseudo-register, increasing the locals count if necessary.
  310. Assert(this->curTmpReg <= this->varRegsCount && this->curTmpReg >= this->firstTmpReg);
  311. Js::RegSlot tmpReg = this->curTmpReg;
  312. UInt32Math::Inc(this->curTmpReg);
  313. if (this->curTmpReg > this->varRegsCount)
  314. {
  315. this->varRegsCount = this->curTmpReg;
  316. }
  317. return tmpReg;
  318. }
  319. void FuncInfo::ReleaseLoc(ParseNode *pnode)
  320. {
  321. // Release the temp assigned to this expression so it can be re-used.
  322. if (pnode && pnode->location != Js::Constants::NoRegister)
  323. {
  324. this->ReleaseTmpRegister(pnode->location);
  325. }
  326. }
  327. void FuncInfo::ReleaseLoad(ParseNode *pnode)
  328. {
  329. // Release any temp register(s) acquired by an EmitLoad.
  330. switch (pnode->nop)
  331. {
  332. case knopDot:
  333. case knopIndex:
  334. case knopCall:
  335. this->ReleaseReference(pnode);
  336. break;
  337. }
  338. this->ReleaseLoc(pnode);
  339. }
  340. void FuncInfo::ReleaseReference(ParseNode *pnode)
  341. {
  342. // Release any temp(s) assigned to this reference expression so they can be re-used.
  343. switch (pnode->nop)
  344. {
  345. case knopDot:
  346. this->ReleaseLoc(pnode->sxBin.pnode1);
  347. break;
  348. case knopIndex:
  349. this->ReleaseLoc(pnode->sxBin.pnode2);
  350. this->ReleaseLoc(pnode->sxBin.pnode1);
  351. break;
  352. case knopName:
  353. // Do nothing (see EmitReference)
  354. break;
  355. case knopCall:
  356. case knopNew:
  357. // For call/new, we have to release the ArgOut register(s) in reverse order,
  358. // but we have the args in a singly linked list.
  359. // Fortunately, we know that the set we have to release is sequential.
  360. // So find the endpoints of the list and release them in descending order.
  361. if (pnode->sxCall.pnodeArgs)
  362. {
  363. ParseNode *pnodeArg = pnode->sxCall.pnodeArgs;
  364. Js::RegSlot firstArg = Js::Constants::NoRegister;
  365. Js::RegSlot lastArg = Js::Constants::NoRegister;
  366. if (pnodeArg->nop == knopList)
  367. {
  368. do
  369. {
  370. if (this->IsTmpReg(pnodeArg->sxBin.pnode1->location))
  371. {
  372. lastArg = pnodeArg->sxBin.pnode1->location;
  373. if (firstArg == Js::Constants::NoRegister)
  374. {
  375. firstArg = lastArg;
  376. }
  377. }
  378. pnodeArg = pnodeArg->sxBin.pnode2;
  379. }
  380. while (pnodeArg->nop == knopList);
  381. }
  382. if (this->IsTmpReg(pnodeArg->location))
  383. {
  384. lastArg = pnodeArg->location;
  385. if (firstArg == Js::Constants::NoRegister)
  386. {
  387. // Just one: first and last point to the same node.
  388. firstArg = lastArg;
  389. }
  390. }
  391. if (lastArg != Js::Constants::NoRegister)
  392. {
  393. Assert(firstArg != Js::Constants::NoRegister);
  394. Assert(lastArg >= firstArg);
  395. do
  396. {
  397. // Walk down from last to first.
  398. this->ReleaseTmpRegister(lastArg);
  399. } while (lastArg-- > firstArg); // these are unsigned, so (--lastArg >= firstArg) will cause an infinite loop if firstArg is 0 (although that shouldn't happen)
  400. }
  401. }
  402. // Now release the call target.
  403. switch (pnode->sxCall.pnodeTarget->nop)
  404. {
  405. case knopDot:
  406. case knopIndex:
  407. this->ReleaseReference(pnode->sxCall.pnodeTarget);
  408. this->ReleaseLoc(pnode->sxCall.pnodeTarget);
  409. break;
  410. default:
  411. this->ReleaseLoad(pnode->sxCall.pnodeTarget);
  412. break;
  413. }
  414. break;
  415. default:
  416. this->ReleaseLoc(pnode);
  417. break;
  418. }
  419. }
  420. void FuncInfo::ReleaseTmpRegister(Js::RegSlot tmpReg)
  421. {
  422. // Put this reg back on top of the temp stack (if it's a temp).
  423. Assert(tmpReg != Js::Constants::NoRegister);
  424. if (this->IsTmpReg(tmpReg))
  425. {
  426. Assert(tmpReg == this->curTmpReg - 1);
  427. this->curTmpReg--;
  428. }
  429. }
  430. Js::RegSlot FuncInfo::InnerScopeToRegSlot(Scope *scope) const
  431. {
  432. Js::RegSlot reg = FirstInnerScopeReg();
  433. Assert(reg != Js::Constants::NoRegister);
  434. uint32 index = scope->GetInnerScopeIndex();
  435. return reg + index;
  436. }
  437. Js::RegSlot FuncInfo::FirstInnerScopeReg() const
  438. {
  439. // FunctionBody stores this as a mapped reg. Callers of this function want the pre-mapped value.
  440. Js::RegSlot reg = this->GetParsedFunctionBody()->GetFirstInnerScopeRegister();
  441. Assert(reg != Js::Constants::NoRegister);
  442. return reg - this->constRegsCount;
  443. }
  444. void FuncInfo::SetFirstInnerScopeReg(Js::RegSlot reg)
  445. {
  446. // Just forward to the FunctionBody.
  447. this->GetParsedFunctionBody()->MapAndSetFirstInnerScopeRegister(reg);
  448. }
  449. void FuncInfo::AddCapturedSym(Symbol *sym)
  450. {
  451. if (this->capturedSyms == nullptr)
  452. {
  453. this->capturedSyms = Anew(alloc, SymbolTable, alloc);
  454. }
  455. this->capturedSyms->AddNew(sym);
  456. }
  457. void FuncInfo::OnStartVisitFunction(ParseNode *pnodeFnc)
  458. {
  459. Assert(pnodeFnc->nop == knopFncDecl);
  460. Assert(this->GetCurrentChildFunction() == nullptr);
  461. this->SetCurrentChildFunction(pnodeFnc->sxFnc.funcInfo);
  462. }
  463. void FuncInfo::OnEndVisitFunction(ParseNode *pnodeFnc)
  464. {
  465. Assert(pnodeFnc->nop == knopFncDecl);
  466. Assert(this->GetCurrentChildFunction() == pnodeFnc->sxFnc.funcInfo);
  467. pnodeFnc->sxFnc.funcInfo->SetCurrentChildScope(nullptr);
  468. this->SetCurrentChildFunction(nullptr);
  469. }
  470. void FuncInfo::OnStartVisitScope(Scope *scope, bool *pisMergedScope)
  471. {
  472. *pisMergedScope = false;
  473. if (scope == nullptr)
  474. {
  475. return;
  476. }
  477. Scope* childScope = this->GetCurrentChildScope();
  478. if (childScope)
  479. {
  480. if (scope->GetScopeType() == ScopeType_Parameter)
  481. {
  482. Assert(childScope->GetEnclosingScope() == scope);
  483. }
  484. else if (childScope->GetScopeType() == ScopeType_Parameter
  485. && childScope->GetCanMergeWithBodyScope()
  486. && scope->GetScopeType() == ScopeType_Block)
  487. {
  488. // If param and body are merged then the class declaration in param scope will have body as the parent
  489. *pisMergedScope = true;
  490. Assert(childScope == scope->GetEnclosingScope()->GetEnclosingScope());
  491. }
  492. else
  493. {
  494. Assert(childScope == scope->GetEnclosingScope());
  495. }
  496. }
  497. this->SetCurrentChildScope(scope);
  498. return;
  499. }
  500. void FuncInfo::OnEndVisitScope(Scope *scope, bool isMergedScope)
  501. {
  502. if (scope == nullptr)
  503. {
  504. return;
  505. }
  506. Assert(this->GetCurrentChildScope() == scope || (scope->GetScopeType() == ScopeType_Parameter && this->GetParamScope() == scope));
  507. this->SetCurrentChildScope(isMergedScope ? scope->GetEnclosingScope()->GetEnclosingScope() : scope->GetEnclosingScope());
  508. }
  509. CapturedSymMap *FuncInfo::EnsureCapturedSymMap()
  510. {
  511. if (this->capturedSymMap == nullptr)
  512. {
  513. this->capturedSymMap = Anew(alloc, CapturedSymMap, alloc);
  514. }
  515. return this->capturedSymMap;
  516. }
  517. void FuncInfo::SetHasMaybeEscapedNestedFunc(DebugOnly(char16 const * reason))
  518. {
  519. if (PHASE_TESTTRACE(Js::StackFuncPhase, this->byteCodeFunction) && !hasEscapedUseNestedFunc)
  520. {
  521. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  522. char16 const * r = _u("");
  523. DebugOnly(r = reason);
  524. Output::Print(_u("HasMaybeEscapedNestedFunc (%s): %s (function %s)\n"),
  525. r,
  526. this->byteCodeFunction->GetDisplayName(),
  527. this->byteCodeFunction->GetDebugNumberSet(debugStringBuffer));
  528. Output::Flush();
  529. }
  530. hasEscapedUseNestedFunc = true;
  531. }
  532. uint FuncInfo::AcquireInnerScopeIndex()
  533. {
  534. uint index = this->currentInnerScopeIndex;
  535. if (index == (uint)-1)
  536. {
  537. index = 0;
  538. }
  539. else
  540. {
  541. index++;
  542. if (index == (uint)-1)
  543. {
  544. Js::Throw::OutOfMemory();
  545. }
  546. }
  547. if (index == this->innerScopeCount)
  548. {
  549. this->innerScopeCount = index + 1;
  550. }
  551. this->currentInnerScopeIndex = index;
  552. return index;
  553. }
  554. void FuncInfo::ReleaseInnerScopeIndex()
  555. {
  556. uint index = this->currentInnerScopeIndex;
  557. Assert(index != (uint)-1);
  558. if (index == 0)
  559. {
  560. index = (uint)-1;
  561. }
  562. else
  563. {
  564. index--;
  565. }
  566. this->currentInnerScopeIndex = index;
  567. }