blob: b04f2cfd24944c2b368ed1915f3b6df076c6d928 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
struct InlineCacheUnit
{
InlineCacheUnit() : loadCacheId((uint)-1), loadMethodCacheId((uint)-1), storeCacheId((uint)-1) {}
union {
struct {
uint loadCacheId;
uint loadMethodCacheId;
uint storeCacheId;
};
struct {
uint cacheId;
};
};
};
typedef JsUtil::BaseDictionary<ParseNode*, SList<Symbol*>*, ArenaAllocator, PowerOf2SizePolicy> CapturedSymMap;
class FuncInfo
{
private:
struct SlotKey
{
Scope* scope;
Js::PropertyId slot;
};
template<class TSlotKey>
class SlotKeyComparer
{
public:
static bool Equals(TSlotKey key1, TSlotKey key2)
{
return (key1.scope == key2.scope && key1.slot == key2.slot);
}
static int GetHashCode(TSlotKey key)
{
return ::Math::PointerCastToIntegralTruncate<int>(key.scope) | key.slot & ArenaAllocator::ObjectAlignmentMask;
}
};
uint inlineCacheCount;
uint rootObjectLoadInlineCacheCount;
uint rootObjectLoadMethodInlineCacheCount;
uint rootObjectStoreInlineCacheCount;
uint isInstInlineCacheCount;
uint referencedPropertyIdCount;
uint NewInlineCache()
{
AssertMsg(this->inlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
return inlineCacheCount++;
}
uint NewRootObjectLoadInlineCache()
{
AssertMsg(this->rootObjectLoadInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
return rootObjectLoadInlineCacheCount++;
}
uint NewRootObjectLoadMethodInlineCache()
{
AssertMsg(this->rootObjectLoadMethodInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
return rootObjectLoadMethodInlineCacheCount++;
}
uint NewRootObjectStoreInlineCache()
{
AssertMsg(this->rootObjectStoreInlineCacheCount < (uint)-2, "Inline cache index wrapped around?");
return rootObjectStoreInlineCacheCount++;
}
uint NewReferencedPropertyId()
{
AssertMsg(this->referencedPropertyIdCount < (uint)-2, "Referenced Property Id index wrapped around?");
return referencedPropertyIdCount++;
}
FuncInfo *currentChildFunction;
Scope *currentChildScope;
SymbolTable *capturedSyms;
CapturedSymMap *capturedSymMap;
uint nextForInLoopLevel;
uint maxForInLoopLevel;
public:
static const Js::RegSlot InitialConstRegsCount = 2; // constRegsCount is set to 2 because R0 is the return register, and R1 is the root object
ArenaAllocator *alloc;
// set in Bind/Assign pass
Js::RegSlot varRegsCount; // number of registers used for non-constants
Js::RegSlot constRegsCount; // number of registers used for constants
Js::ArgSlot inArgsCount; // number of in args (including 'this')
Js::RegSlot outArgsMaxDepth; // max depth of out args stack
Js::RegSlot outArgsCurrentExpr; // max number of out args accumulated in the current nested expression
uint innerScopeCount;
uint currentInnerScopeIndex;
#if DBG
uint32 outArgsDepth; // number of calls nested in an expression
#endif
const char16 *name; // name of the function
Js::RegSlot nullConstantRegister; // location, if any, of enregistered null constant
Js::RegSlot undefinedConstantRegister; // location, if any, of enregistered undefined constant
Js::RegSlot trueConstantRegister; // location, if any, of enregistered true constant
Js::RegSlot falseConstantRegister; // location, if any, of enregistered false constant
Js::RegSlot thisPointerRegister; // location, if any, of this pointer
Js::RegSlot superRegister; // location, if any, of the super reference
Js::RegSlot superCtorRegister; // location, if any, of the superCtor reference
Js::RegSlot newTargetRegister; // location, if any, of the new.target reference
private:
Js::RegSlot envRegister; // location, if any, of the closure environment
public:
Js::RegSlot frameObjRegister; // location, if any, of the heap-allocated local frame
Js::RegSlot frameSlotsRegister; // location, if any, of the heap-allocated local frame
Js::RegSlot paramSlotsRegister; // location, if any, of the heap allocated local frame for param scope
Js::RegSlot frameDisplayRegister; // location, if any, of the display of nested frames
Js::RegSlot funcObjRegister;
Js::RegSlot localClosureReg;
Js::RegSlot yieldRegister;
Js::RegSlot firstTmpReg;
Js::RegSlot curTmpReg;
int argsPlaceHolderSlotCount; // count of place holder slots for same name args and destructuring patterns
Js::RegSlot firstThunkArgReg;
short thunkArgCount;
short staticFuncId;
uint callsEval : 1;
uint childCallsEval : 1;
uint hasArguments : 1;
uint hasHeapArguments : 1;
uint isTopLevelEventHandler : 1;
uint hasLocalInClosure : 1;
uint hasClosureReference : 1;
uint hasCachedScope : 1;
uint funcExprNameReference : 1;
uint applyEnclosesArgs : 1;
uint escapes : 1;
uint hasDeferredChild : 1; // switch for DeferNested to persist outer scopes
uint hasRedeferrableChild : 1;
uint hasLoop : 1;
uint hasEscapedUseNestedFunc : 1;
uint needEnvRegister : 1;
uint isBodyAndParamScopeMerged : 1;
#if DBG
// FunctionBody was reused on recompile of a redeferred enclosing function.
uint isReused:1;
#endif
typedef JsUtil::BaseDictionary<uint, Js::RegSlot, ArenaAllocator, PrimeSizePolicy> ConstantRegisterMap;
ConstantRegisterMap constantToRegister; // maps uint constant to register
typedef JsUtil::BaseDictionary<IdentPtr, Js::RegSlot, ArenaAllocator> PidRegisterMap;
PidRegisterMap stringToRegister; // maps string constant to register
typedef JsUtil::BaseDictionary<double,Js::RegSlot, ArenaAllocator, PrimeSizePolicy> DoubleRegisterMap;
DoubleRegisterMap doubleConstantToRegister; // maps double constant to register
typedef JsUtil::BaseDictionary<ParseNodePtr, Js::RegSlot, ArenaAllocator, PowerOf2SizePolicy, Js::StringTemplateCallsiteObjectComparer> StringTemplateCallsiteRegisterMap;
StringTemplateCallsiteRegisterMap stringTemplateCallsiteRegisterMap; // maps string template callsite constant to register
Scope *paramScope; // top level scope for parameter default values
Scope *bodyScope; // top level scope of the function body
Scope *funcExprScope;
ParseNode *root; // top-level AST for function
Js::ParseableFunctionInfo* byteCodeFunction; // reference to generated bytecode function (could be defer parsed or actually parsed)
SList<ParseNode*> targetStatements; // statements that are targets of jumps (break or continue)
Js::ByteCodeLabel singleExit;
typedef SList<InlineCacheUnit> InlineCacheList;
typedef JsUtil::BaseDictionary<Js::PropertyId, InlineCacheList*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheIdMap;
typedef JsUtil::BaseDictionary<Js::RegSlot, InlineCacheIdMap*, ArenaAllocator, PowerOf2SizePolicy> InlineCacheMap;
typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> RootObjectInlineCacheIdMap;
typedef JsUtil::BaseDictionary<Js::PropertyId, uint, ArenaAllocator, PowerOf2SizePolicy> ReferencedPropertyIdMap;
RootObjectInlineCacheIdMap * rootObjectLoadInlineCacheMap;
RootObjectInlineCacheIdMap * rootObjectLoadMethodInlineCacheMap;
RootObjectInlineCacheIdMap * rootObjectStoreInlineCacheMap;
InlineCacheMap * inlineCacheMap;
ReferencedPropertyIdMap * referencedPropertyIdToMapIndex;
SListBase<uint> valueOfStoreCacheIds;
SListBase<uint> toStringStoreCacheIds;
typedef JsUtil::BaseDictionary<SlotKey, Js::ProfileId, ArenaAllocator, PowerOf2SizePolicy, SlotKeyComparer> SlotProfileIdMap;
SlotProfileIdMap slotProfileIdMap;
Js::PropertyId thisScopeSlot;
Js::PropertyId superScopeSlot;
Js::PropertyId superCtorScopeSlot;
Js::PropertyId newTargetScopeSlot;
bool isThisLexicallyCaptured;
bool isSuperLexicallyCaptured;
bool isSuperCtorLexicallyCaptured;
bool isNewTargetLexicallyCaptured;
Symbol *argumentsSymbol;
JsUtil::List<Js::RegSlot, ArenaAllocator> nonUserNonTempRegistersToInitialize;
FuncInfo(
const char16 *name,
ArenaAllocator *alloc,
Scope *paramScope,
Scope *bodyScope,
ParseNode *pnode,
Js::ParseableFunctionInfo* byteCodeFunction);
uint NewIsInstInlineCache() { return isInstInlineCacheCount++; }
uint GetInlineCacheCount() const { return this->inlineCacheCount; }
uint GetRootObjectLoadInlineCacheCount() const { return this->rootObjectLoadInlineCacheCount; }
uint GetRootObjectLoadMethodInlineCacheCount() const { return this->rootObjectLoadMethodInlineCacheCount; }
uint GetRootObjectStoreInlineCacheCount() const { return this->rootObjectStoreInlineCacheCount; }
uint GetIsInstInlineCacheCount() const { return this->isInstInlineCacheCount; }
uint GetReferencedPropertyIdCount() const { return this->referencedPropertyIdCount; }
void SetFirstTmpReg(Js::RegSlot tmpReg)
{
Assert(this->firstTmpReg == Js::Constants::NoRegister);
Assert(this->curTmpReg == Js::Constants::NoRegister);
this->firstTmpReg = tmpReg;
this->curTmpReg = tmpReg;
}
bool IsTmpReg(Js::RegSlot tmpReg)
{
Assert(this->firstTmpReg != Js::Constants::NoRegister);
return !RegIsConst(tmpReg) && tmpReg >= firstTmpReg;
}
bool RegIsConst(Js::RegSlot reg)
{
// varRegsCount includes the tmp regs, so if reg number is larger than that,
// then it must be in the negative range for const.
return reg >= varRegsCount;
}
Js::RegSlot NextVarRegister()
{
AssertMsg(this->firstTmpReg == Js::Constants::NoRegister, "Shouldn't assign var register after we start allocating temp reg");
Js::RegSlot reg = varRegsCount;
UInt32Math::Inc(varRegsCount);
return REGSLOT_TO_VARREG(reg);
}
Js::RegSlot NextConstRegister()
{
AssertMsg(this->firstTmpReg == Js::Constants::NoRegister, "Shouldn't assign var register after we start allocating temp reg");
Js::RegSlot reg = constRegsCount;
UInt32Math::Inc(constRegsCount);
return REGSLOT_TO_CONSTREG(reg);
}
Js::RegSlot RegCount() const
{
return constRegsCount + varRegsCount;
}
uint InnerScopeCount() const { return innerScopeCount; }
uint CurrentInnerScopeIndex() const { return currentInnerScopeIndex; }
uint AcquireInnerScopeIndex();
void ReleaseInnerScopeIndex();
bool GetApplyEnclosesArgs() const { return applyEnclosesArgs; }
void SetApplyEnclosesArgs(bool b) { applyEnclosesArgs=b; }
bool IsGlobalFunction() const;
// Fake global ->
// 1) new Function code's global code
// 2) global code generated from the reparsing deferred parse function
bool IsFakeGlobalFunction(uint32 flags) const
{
return IsGlobalFunction() && !(flags & fscrGlobalCode);
}
Scope *GetBodyScope() const
{
return bodyScope;
}
void SetBodyScope(Scope * scope)
{
bodyScope = scope;
}
Scope *GetParamScope() const
{
return paramScope;
}
void SetParamScope(Scope * scope)
{
paramScope = scope;
}
Scope *GetTopLevelScope() const
{
// Top level scope will be the same for knopProg and knopFncDecl.
return paramScope;
}
Scope* GetFuncExprScope() const
{
return funcExprScope;
}
void SetFuncExprScope(Scope* funcExprScope) {
this->funcExprScope = funcExprScope;
}
Symbol *GetArgumentsSymbol() const
{
return argumentsSymbol;
}
void SetArgumentsSymbol(Symbol *sym)
{
Assert(argumentsSymbol == nullptr || argumentsSymbol == sym);
argumentsSymbol = sym;
}
bool GetCallsEval() const {
return callsEval;
}
void SetCallsEval(bool does) {
callsEval = does;
}
bool GetHasArguments() const {
return hasArguments;
}
void SetHasArguments(bool has) {
hasArguments = has;
}
bool GetHasHeapArguments() const
{
return hasHeapArguments;
}
void SetHasHeapArguments(bool has, bool optArgInBackend = false)
{
hasHeapArguments = has;
byteCodeFunction->SetDoBackendArgumentsOptimization(optArgInBackend);
}
bool GetIsTopLevelEventHandler() const {
return isTopLevelEventHandler;
}
void SetIsTopLevelEventHandler(bool is) {
isTopLevelEventHandler = is;
}
bool GetChildCallsEval() const {
return childCallsEval;
}
void SetChildCallsEval(bool does) {
childCallsEval = does;
}
bool GetHasLocalInClosure() const {
return hasLocalInClosure;
}
void SetHasLocalInClosure(bool has) {
hasLocalInClosure = has;
}
bool GetHasClosureReference() const {
return hasClosureReference;
}
void SetHasCachedScope(bool has) {
hasCachedScope = has;
}
bool GetHasCachedScope() const {
return hasCachedScope;
}
void SetFuncExprNameReference(bool has) {
funcExprNameReference = has;
}
bool GetFuncExprNameReference() const {
return funcExprNameReference;
}
void SetHasClosureReference(bool has) {
hasClosureReference = has;
}
bool GetIsStrictMode() const {
return this->byteCodeFunction->GetIsStrictMode();
}
bool Escapes() const {
return escapes;
}
void SetEscapes(bool does) {
escapes = does;
}
bool HasMaybeEscapedNestedFunc() const {
return hasEscapedUseNestedFunc;
}
void SetHasMaybeEscapedNestedFunc(DebugOnly(char16 const * reason));
bool IsDeferred() const;
bool IsRestored()
{
// FuncInfo are from RestoredScopeInfo
return root == nullptr;
}
bool HasDeferredChild() const {
return hasDeferredChild;
}
void SetHasDeferredChild() {
hasDeferredChild = true;
}
bool HasRedeferrableChild() const {
return hasRedeferrableChild;
}
void SetHasRedeferrableChild() {
hasRedeferrableChild = true;
}
bool IsRedeferrable() const;
Js::FunctionBody* GetParsedFunctionBody() const
{
AssertMsg(this->byteCodeFunction->IsFunctionParsed(), "Function must be parsed in order to call this method");
Assert(!IsDeferred() || this->byteCodeFunction->GetFunctionBody()->GetByteCode() != nullptr);
return this->byteCodeFunction->GetFunctionBody();
}
bool IsBodyAndParamScopeMerged() const {
return isBodyAndParamScopeMerged;
}
void ResetBodyAndParamScopeMerged() {
isBodyAndParamScopeMerged = false;
}
BOOL HasSuperReference() const;
BOOL HasDirectSuper() const;
BOOL IsClassMember() const;
BOOL IsLambda() const;
BOOL IsClassConstructor() const;
BOOL IsBaseClassConstructor() const;
void RemoveTargetStmt(ParseNode* pnodeStmt) {
targetStatements.Remove(pnodeStmt);
}
void AddTargetStmt(ParseNode *pnodeStmt) {
targetStatements.Prepend(pnodeStmt);
}
Js::RegSlot LookupDouble(double d) {
return doubleConstantToRegister.Lookup(d,Js::Constants::NoRegister);
}
bool TryGetDoubleLoc(double d, Js::RegSlot *loc) {
Js::RegSlot ret=LookupDouble(d);
*loc=ret;
return(ret!=Js::Constants::NoRegister);
}
void AddDoubleConstant(double d, Js::RegSlot location) {
doubleConstantToRegister.Item(d,location);
}
bool NeedEnvRegister() const { return this->needEnvRegister; }
void SetNeedEnvRegister() { this->needEnvRegister = true; };
Js::RegSlot GetEnvRegister() const
{
Assert(this->envRegister != Js::Constants::NoRegister);
return this->envRegister;
}
Js::RegSlot AssignEnvRegister(bool constReg)
{
Assert(needEnvRegister);
Assert(this->envRegister == Js::Constants::NoRegister);
Js::RegSlot reg = constReg? NextConstRegister() : NextVarRegister();
this->envRegister = reg;
return reg;
}
Js::RegSlot AssignThisRegister()
{
if (this->thisPointerRegister == Js::Constants::NoRegister)
{
this->thisPointerRegister = NextVarRegister();
}
return this->thisPointerRegister;
}
Js::RegSlot AssignSuperRegister()
{
if (this->superRegister == Js::Constants::NoRegister)
{
this->superRegister = NextVarRegister();
}
return this->superRegister;
}
Js::RegSlot AssignSuperCtorRegister()
{
if (this->superCtorRegister == Js::Constants::NoRegister)
{
this->superCtorRegister = NextVarRegister();
}
return this->superCtorRegister;
}
Js::RegSlot AssignNewTargetRegister()
{
if (this->newTargetRegister == Js::Constants::NoRegister)
{
this->newTargetRegister = NextVarRegister();
}
return this->newTargetRegister;
}
Js::RegSlot AssignNullConstRegister()
{
if (this->nullConstantRegister == Js::Constants::NoRegister)
{
this->nullConstantRegister = NextConstRegister();
}
return this->nullConstantRegister;
}
Js::RegSlot AssignUndefinedConstRegister()
{
if (this->undefinedConstantRegister == Js::Constants::NoRegister)
{
this->undefinedConstantRegister = NextConstRegister();
}
return this->undefinedConstantRegister;
}
Js::RegSlot AssignTrueConstRegister()
{
if (this->trueConstantRegister == Js::Constants::NoRegister)
{
this->trueConstantRegister = NextConstRegister();
}
return this->trueConstantRegister;
}
Js::RegSlot AssignFalseConstRegister()
{
if (this->falseConstantRegister == Js::Constants::NoRegister)
{
this->falseConstantRegister = NextConstRegister();
}
return this->falseConstantRegister;
}
Js::RegSlot AssignYieldRegister()
{
AssertMsg(this->yieldRegister == Js::Constants::NoRegister, "yield register should only be assigned once by FinalizeRegisters()");
this->yieldRegister = NextVarRegister();
return this->yieldRegister;
}
Js::RegSlot GetLocalScopeSlotsReg()
{
return this->localClosureReg;
}
Js::RegSlot GetLocalFrameDisplayReg()
{
return this->localClosureReg + 1;
}
Js::RegSlot InnerScopeToRegSlot(Scope *scope) const;
Js::RegSlot FirstInnerScopeReg() const;
void SetFirstInnerScopeReg(Js::RegSlot reg);
void StartRecordingOutArgs(unsigned int argCount)
{
#if DBG
outArgsDepth++;
#endif
// We should have checked for argCount overflow already
Assert(argCount == (Js::ArgSlot)argCount);
// Add one for the space to save the m_outParams pointer in InterpreterStackFrame::PushOut
unsigned int outArgsCount = argCount + 1;
outArgsCurrentExpr += (Js::ArgSlot)outArgsCount;
// Check for overflow
if ((Js::ArgSlot)outArgsCount != outArgsCount || outArgsCurrentExpr < outArgsCount)
{
Js::Throw::OutOfMemory();
}
outArgsMaxDepth = max(outArgsMaxDepth, outArgsCurrentExpr);
}
void EndRecordingOutArgs(Js::ArgSlot argCount)
{
AssertMsg(outArgsDepth > 0, "mismatched Start and End");
Assert(outArgsCurrentExpr >= argCount);
#if DBG
outArgsDepth--;
#endif
// Add one to pop the space to save the m_outParams pointer
outArgsCurrentExpr -= (argCount + 1);
Assert(outArgsDepth != 0 || outArgsCurrentExpr == 0);
}
uint GetMaxForInLoopLevel() const { return this->maxForInLoopLevel; }
uint AcquireForInLoopLevel()
{
uint forInLoopLevel = this->nextForInLoopLevel++;
this->maxForInLoopLevel = max(this->maxForInLoopLevel, this->nextForInLoopLevel);
return forInLoopLevel;
}
void ReleaseForInLoopLevel(uint forInLoopLevel)
{
Assert(this->nextForInLoopLevel == forInLoopLevel + 1);
this->nextForInLoopLevel = forInLoopLevel;
}
Js::RegSlot AcquireLoc(ParseNode *pnode);
Js::RegSlot AcquireTmpRegister();
void ReleaseLoc(ParseNode *pnode);
void ReleaseReference(ParseNode *pnode);
void ReleaseLoad(ParseNode *pnode);
void ReleaseTmpRegister(Js::RegSlot tmpReg);
uint FindOrAddReferencedPropertyId(Js::PropertyId propertyId);
uint FindOrAddRootObjectInlineCacheId(Js::PropertyId propertyId, bool isLoadMethod, bool isStore);
uint FindOrAddInlineCacheId(Js::RegSlot instanceSlot, Js::PropertyId propertySlot, bool isLoadMethod, bool isStore)
{
Assert(instanceSlot != Js::Constants::NoRegister);
Assert(propertySlot != Js::Constants::NoProperty);
Assert(!isLoadMethod || !isStore);
InlineCacheIdMap *properties;
uint cacheId;
if (isStore)
{
// ... = foo.toString;
// foo.toString = ...;
// We need a new cache here to ensure SetProperty() is called, which will set the side-effect bit
// on the scriptContext.
switch (propertySlot)
{
case Js::PropertyIds::valueOf:
cacheId = this->NewInlineCache();
valueOfStoreCacheIds.Prepend(alloc, cacheId);
return cacheId;
case Js::PropertyIds::toString:
cacheId = this->NewInlineCache();
toStringStoreCacheIds.Prepend(alloc, cacheId);
return cacheId;
};
}
if (!inlineCacheMap->TryGetValue(instanceSlot, &properties))
{
properties = Anew(alloc, InlineCacheIdMap, alloc, 17);
inlineCacheMap->Add(instanceSlot, properties);
}
InlineCacheList* cacheList;
if (!properties->TryGetValue(propertySlot, &cacheList))
{
cacheList = Anew(alloc, InlineCacheList, alloc);
properties->Add(propertySlot, cacheList);
}
// If we share inline caches we should never have more than one entry in the list.
Assert(Js::FunctionBody::ShouldShareInlineCaches() || cacheList->Count() <= 1);
InlineCacheUnit cacheIdUnit;
if (Js::FunctionBody::ShouldShareInlineCaches() && !cacheList->Empty())
{
cacheIdUnit = cacheList->Head();
if (isLoadMethod)
{
if (cacheIdUnit.loadMethodCacheId == (uint)-1)
{
cacheIdUnit.loadMethodCacheId = this->NewInlineCache();
}
cacheId = cacheIdUnit.loadMethodCacheId;
}
else if (isStore)
{
if (cacheIdUnit.storeCacheId == (uint)-1)
{
cacheIdUnit.storeCacheId = this->NewInlineCache();
}
cacheId = cacheIdUnit.storeCacheId;
}
else
{
if (cacheIdUnit.loadCacheId == (uint)-1)
{
cacheIdUnit.loadCacheId = this->NewInlineCache();
}
cacheId = cacheIdUnit.loadCacheId;
}
cacheList->Head() = cacheIdUnit;
}
else
{
cacheId = this->NewInlineCache();
if (Js::FunctionBody::ShouldShareInlineCaches())
{
if (isLoadMethod)
{
cacheIdUnit.loadCacheId = (uint)-1;
cacheIdUnit.loadMethodCacheId = cacheId;
cacheIdUnit.storeCacheId = (uint)-1;
}
else if (isStore)
{
cacheIdUnit.loadCacheId = (uint)-1;
cacheIdUnit.loadMethodCacheId = (uint)-1;
cacheIdUnit.storeCacheId = cacheId;
}
else
{
cacheIdUnit.loadCacheId = cacheId;
cacheIdUnit.loadMethodCacheId = (uint)-1;
cacheIdUnit.storeCacheId = (uint)-1;
}
}
else
{
cacheIdUnit.cacheId = cacheId;
}
cacheList->Prepend(cacheIdUnit);
}
return cacheId;
}
Js::ProfileId FindOrAddSlotProfileId(Scope* scope, Js::PropertyId propertyId)
{
SlotKey key;
key.scope = scope;
key.slot = propertyId;
Js::ProfileId profileId = Js::Constants::NoProfileId;
if (!this->slotProfileIdMap.TryGetValue(key, &profileId))
{
Assert(this->byteCodeFunction->IsFunctionParsed());
if (this->byteCodeFunction->GetFunctionBody()->AllocProfiledSlotId(&profileId))
{
this->slotProfileIdMap.Add(key, profileId);
}
}
return profileId;
}
void EnsureThisScopeSlot();
void EnsureSuperScopeSlot();
void EnsureSuperCtorScopeSlot();
void EnsureNewTargetScopeSlot();
void SetIsThisLexicallyCaptured()
{
this->isThisLexicallyCaptured = true;
}
void SetIsSuperLexicallyCaptured()
{
this->isSuperLexicallyCaptured = true;
}
void SetIsSuperCtorLexicallyCaptured()
{
this->isSuperCtorLexicallyCaptured = true;
}
void SetIsNewTargetLexicallyCaptured()
{
this->isNewTargetLexicallyCaptured = true;
}
Scope * GetGlobalBlockScope() const;
Scope * GetGlobalEvalBlockScope() const;
FuncInfo *GetCurrentChildFunction() const
{
return this->currentChildFunction;
}
void SetCurrentChildFunction(FuncInfo *funcInfo)
{
this->currentChildFunction = funcInfo;
}
Scope *GetCurrentChildScope() const
{
return this->currentChildScope;
}
void SetCurrentChildScope(Scope *scope)
{
this->currentChildScope = scope;
}
SymbolTable *GetCapturedSyms() const { return capturedSyms; }
void OnStartVisitFunction(ParseNode *pnodeFnc);
void OnEndVisitFunction(ParseNode *pnodeFnc);
void OnStartVisitScope(Scope *scope, bool *pisMergedScope);
void OnEndVisitScope(Scope *scope, bool isMergedScope = false);
void AddCapturedSym(Symbol *sym);
CapturedSymMap *EnsureCapturedSymMap();
#if DBG_DUMP
void Dump();
#endif
};