| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- //-------------------------------------------------------------------------------------------------------
- // 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 thisConstantRegister; // location, if any, of enregistered 'this' constant
- 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
- uint canDefer : 1;
- 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 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> BigIntRegisterMap;
- BigIntRegisterMap bigintToRegister; // maps bigint constant to register
- typedef JsUtil::BaseDictionary<ParseNodePtr, Js::RegSlot, ArenaAllocator, PowerOf2SizePolicy> 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;
- ParseNodeFnc *root; // top-level AST for function
- Js::ParseableFunctionInfo* byteCodeFunction; // reference to generated bytecode function (could be defer parsed or actually parsed)
- SList<ParseNodeStmt*> 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;
- Symbol *argumentsSymbol;
- Symbol *thisSymbol;
- Symbol *newTargetSymbol;
- Symbol *superSymbol;
- Symbol *superConstructorSymbol;
- JsUtil::List<Js::RegSlot, ArenaAllocator> nonUserNonTempRegistersToInitialize;
- FuncInfo(
- const char16 *name,
- ArenaAllocator *alloc,
- ByteCodeGenerator *byteCodeGenerator,
- Scope *paramScope,
- Scope *bodyScope,
- ParseNodeFnc *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;
- }
- void SetThisSymbol(Symbol *sym)
- {
- Assert(thisSymbol == nullptr || thisSymbol == sym);
- thisSymbol = sym;
- }
- Symbol* GetThisSymbol() const
- {
- return thisSymbol;
- }
- void SetNewTargetSymbol(Symbol *sym)
- {
- Assert(newTargetSymbol == nullptr || newTargetSymbol == sym);
- newTargetSymbol = sym;
- }
- Symbol* GetNewTargetSymbol() const
- {
- return newTargetSymbol;
- }
- void SetSuperSymbol(Symbol *sym)
- {
- Assert(superSymbol == nullptr || superSymbol == sym);
- superSymbol = sym;
- }
- Symbol* GetSuperSymbol() const
- {
- return superSymbol;
- }
- void SetSuperConstructorSymbol(Symbol *sym)
- {
- Assert(superConstructorSymbol == nullptr || superConstructorSymbol == sym);
- superConstructorSymbol = sym;
- }
- Symbol* GetSuperConstructorSymbol() const
- {
- return superConstructorSymbol;
- }
- 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;
- }
- 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;
- BOOL IsDerivedClassConstructor() const;
- void RemoveTargetStmt(ParseNodeStmt* pnodeStmt) {
- targetStatements.Remove(pnodeStmt);
- }
- void AddTargetStmt(ParseNodeStmt *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 AssignThisConstRegister()
- {
- if (this->thisConstantRegister == Js::Constants::NoRegister)
- {
- this->thisConstantRegister = this->NextVarRegister();
- }
- return this->thisConstantRegister;
- }
- 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;
- }
- 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(ParseNodeFnc *pnodeFnc);
- void OnEndVisitFunction(ParseNodeFnc *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
- };
|