| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- #define TypeWithAuxSlotTag(_t) \
- (reinterpret_cast<Type*>(reinterpret_cast<size_t>(_t) | InlineCacheAuxSlotTypeTag))
- #define TypeWithoutAuxSlotTag(_t) \
- (reinterpret_cast<Js::Type*>(reinterpret_cast<size_t>(_t) & ~InlineCacheAuxSlotTypeTag))
- #define TypeHasAuxSlotTag(_t) \
- (!!(reinterpret_cast<size_t>(_t) & InlineCacheAuxSlotTypeTag))
- // forward decl
- class JITType;
- struct InlineCacheData;
- template <class TAllocator> class JITTypeHolderBase;
- typedef JITTypeHolderBase<void> JITTypeHolder;
- typedef JITTypeHolderBase<Recycler> RecyclerJITTypeHolder;
- namespace Js
- {
- enum CacheType : byte
- {
- CacheType_None,
- CacheType_Local,
- CacheType_Proto,
- CacheType_LocalWithoutProperty,
- CacheType_Getter,
- CacheType_Setter,
- CacheType_TypeProperty,
- };
- enum SlotType : byte
- {
- SlotType_None,
- SlotType_Inline,
- SlotType_Aux,
- };
- struct PropertyCacheOperationInfo
- {
- PropertyCacheOperationInfo()
- : cacheType(CacheType_None), slotType(SlotType_None), isPolymorphic(false)
- {
- }
- CacheType cacheType;
- SlotType slotType;
- bool isPolymorphic;
- };
- struct JitTimeInlineCache;
- struct InlineCache
- {
- static const int CacheLayoutSelectorBitCount = 1;
- static const int RequiredAuxSlotCapacityBitCount = 15;
- static const bool IsPolymorphic = false;
- InlineCache() {}
- union
- {
- // Invariants:
- // - Type* fields do not overlap.
- // - "next" field is non-null iff the cache is linked in a list of proto-caches
- // (see ScriptContext::RegisterProtoInlineCache and ScriptContext::InvalidateProtoCaches).
- struct s_local
- {
- Type* type;
- // PatchPutValue caches here the type the object has before a new property is added.
- // If this type is hit again we can immediately change the object's type to "type"
- // and store the value into the slot "slotIndex".
- Type* typeWithoutProperty;
- union
- {
- struct
- {
- uint16 isLocal : 1;
- uint16 requiredAuxSlotCapacity : 15; // Maximum auxiliary slot capacity (for a path type) must be < 2^16
- };
- struct
- {
- uint16 rawUInt16; // Required for access from JIT-ed code
- };
- };
- uint16 slotIndex;
- } local;
- struct s_proto
- {
- uint16 isProto : 1;
- uint16 isMissing : 1;
- uint16 unused : 14;
- uint16 slotIndex;
- // It's OK for the type in proto layout to overlap with typeWithoutProperty in the local layout, because
- // we only use typeWithoutProperty on field stores, which can never have a proto layout.
- Type* type;
- DynamicObject* prototypeObject;
- } proto;
- struct s_accessor
- {
- DynamicObject *object;
- union
- {
- struct {
- uint16 isAccessor : 1;
- uint16 flags : 2;
- uint16 isOnProto : 1;
- uint16 unused : 12;
- };
- uint16 rawUInt16;
- };
- uint16 slotIndex;
- Type * type;
- } accessor;
- CompileAssert(sizeof(s_local) == sizeof(s_proto));
- CompileAssert(sizeof(s_local) == sizeof(s_accessor));
- } u;
- InlineCache** invalidationListSlotPtr;
- bool IsEmpty() const
- {
- return u.local.type == nullptr;
- }
- bool IsLocal() const
- {
- return u.local.isLocal;
- }
- bool IsProto() const
- {
- return u.proto.isProto;
- }
- DynamicObject * GetPrototypeObject() const
- {
- Assert(IsProto());
- return u.proto.prototypeObject;
- }
- DynamicObject * GetAccessorObject() const
- {
- Assert(IsAccessor());
- return u.accessor.object;
- }
- bool IsAccessor() const
- {
- return u.accessor.isAccessor;
- }
- bool IsAccessorOnProto() const
- {
- return IsAccessor() && u.accessor.isOnProto;
- }
- bool IsGetterAccessor() const
- {
- return IsAccessor() && !!(u.accessor.flags & InlineCacheGetterFlag);
- }
- bool IsGetterAccessorOnProto() const
- {
- return IsGetterAccessor() && u.accessor.isOnProto;
- }
- bool IsSetterAccessor() const
- {
- return IsAccessor() && !!(u.accessor.flags & InlineCacheSetterFlag);
- }
- bool IsSetterAccessorOnProto() const
- {
- return IsSetterAccessor() && u.accessor.isOnProto;
- }
- Type* GetRawType() const
- {
- return IsLocal() ? u.local.type : (IsProto() ? u.proto.type : (IsAccessor() ? u.accessor.type : nullptr));
- }
- Type* GetType() const
- {
- return TypeWithoutAuxSlotTag(GetRawType());
- }
- template<bool isAccessor>
- bool HasDifferentType(const bool isProto, const Type * type, const Type * typeWithoutProperty) const;
- bool HasType_Flags(const Type * type) const
- {
- return u.accessor.type == type || u.accessor.type == TypeWithAuxSlotTag(type);
- }
- bool HasDifferentType(const Type * type) const
- {
- return !IsEmpty() && GetType() != type;
- }
- bool RemoveFromInvalidationList()
- {
- if (this->invalidationListSlotPtr == nullptr)
- {
- return false;
- }
- Assert(*this->invalidationListSlotPtr == this);
- *this->invalidationListSlotPtr = nullptr;
- this->invalidationListSlotPtr = nullptr;
- return true;
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- const char16 *LayoutString() const
- {
- if (IsEmpty())
- {
- return _u("Empty");
- }
- if (IsLocal())
- {
- return _u("Local");
- }
- if (IsAccessor())
- {
- return _u("Accessor");
- }
- return _u("Proto");
- }
- #endif
- public:
- void CacheLocal(
- Type *const type,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- Type *const typeWithoutProperty,
- int requiredAuxSlotCapacity,
- ScriptContext *const requestContext);
- void CacheProto(
- DynamicObject *const prototypeObjectWithProperty,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- const bool isMissing,
- Type *const type,
- ScriptContext *const requestContext);
- void CacheAccessor(
- const bool isGetter,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- Type *const type,
- DynamicObject *const object,
- const bool isOnProto,
- ScriptContext *const requestContext);
- template<
- bool CheckLocal,
- bool CheckProto,
- bool CheckAccessor,
- bool CheckMissing,
- bool ReturnOperationInfo,
- bool OutputExistence /*When set, propertyValue is true or false, representing whether the property exists on the instance not its actual value*/>
- bool TryGetProperty(
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo *const operationInfo);
- template<
- bool CheckLocal,
- bool CheckLocalTypeWithoutProperty,
- bool CheckAccessor,
- bool ReturnOperationInfo>
- bool TrySetProperty(
- RecyclableObject *const object,
- const PropertyId propertyId,
- Var propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo *const operationInfo,
- const PropertyOperationFlags propertyOperationFlags = PropertyOperation_None);
- bool PretendTryGetProperty(Type *const type, PropertyCacheOperationInfo * operationInfo) const;
- bool PretendTrySetProperty(Type *const type, Type *const oldType, PropertyCacheOperationInfo * operationInfo) const;
- void Clear();
- void RemoveFromInvalidationListAndClear(ThreadContext* threadContext);
- template <class TAllocator>
- InlineCache *Clone(TAllocator *const allocator);
- InlineCache *Clone(Js::PropertyId propertyId, ScriptContext* scriptContext);
- void CopyTo(PropertyId propertyId, ScriptContext * scriptContext, InlineCache * const clone);
- #if ENABLE_FIXED_FIELDS
- bool TryGetFixedMethodFromCache(Js::FunctionBody* functionBody, uint cacheId, Js::JavascriptFunction** pFixedMethod);
- #endif
- bool GetGetterSetter(RecyclableObject *object, RecyclableObject **callee);
- bool GetCallApplyTarget(RecyclableObject* obj, RecyclableObject **callee);
- static uint GetGetterFlagMask()
- {
- // First bit is marked for isAccessor in the accessor cache layout.
- return InlineCacheGetterFlag << 1;
- }
- static uint GetSetterFlagMask()
- {
- // First bit is marked for isAccessor in the accessor cache layout.
- return InlineCacheSetterFlag << 1;
- }
- static uint GetGetterSetterFlagMask()
- {
- // First bit is marked for isAccessor in the accessor cache layout.
- return (InlineCacheGetterFlag | InlineCacheSetterFlag) << 1;
- }
- static uint GetIsOnProtoFlagMask()
- {
- return InlineCacheIsOnProtoFlag << 1;
- }
- bool NeedsToBeRegisteredForProtoInvalidation() const;
- bool NeedsToBeRegisteredForStoreFieldInvalidation() const;
- #if DEBUG
- bool ConfirmCacheMiss(const Type * oldType, const PropertyValueInfo* info) const;
- bool NeedsToBeRegisteredForInvalidation() const;
- static void VerifyRegistrationForInvalidation(const InlineCache* cache, ScriptContext* scriptContext, Js::PropertyId propertyId);
- #endif
- #if DBG_DUMP
- void Dump();
- #endif
- private:
- // Write operation info if relevant
- template<bool ReturnOperationInfo> inline static void OutputOperationInfo(PropertyCacheOperationInfo *const operationInfo, CacheType cacheType, SlotType slotType);
- // Get the source object that supplies property values, based on the cache type and the starting object
- template<CacheType cacheType> inline DynamicObject* GetSourceObject(RecyclableObject *const propertyObject);
- // Get the source object that we should test for script context matching, based on the cache type and the starting object
- template<CacheType cacheType> inline RecyclableObject* GetSourceObjectForScriptContext(RecyclableObject *const propertyObject);
- // Get the slot index for the property, based on the cache type
- template<CacheType cacheType> inline int GetSlotIndex();
- // Get the property value, based on the source object and slot index
- template<SlotType slotType> inline static Var GetPropertyValue(DynamicObject* sourceObject, int slotIndex);
- // Set the output propertyValue and operationInfo
- template<
- bool OutputExistence,
- bool IsMissing,
- bool ReturnOperationInfo,
- CacheType cacheType,
- SlotType slotType>
- void OutputPropertyValueAndOperationInfo(
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo *const operationInfo)
- {
- Assert(this->GetSourceObjectForScriptContext<cacheType>(propertyObject)->GetScriptContext() == requestContext); // we never cache a type from another script context
- OutputPropertyValue<OutputExistence, IsMissing, cacheType, slotType>::impl(this, instance, propertyObject, propertyId, propertyValue, requestContext);
- OutputOperationInfo<ReturnOperationInfo>(operationInfo, cacheType, slotType);
- }
- // Because C++ can't partially specialize functions, here's a struct. Calling the impl method on this struct
- // will set the output propertyValue.
- template<
- bool OutputExistence,
- bool IsMissing,
- CacheType cacheType,
- SlotType slotType>
- struct OutputPropertyValue {};
- template<bool IsMissing, CacheType cacheType, SlotType slotType>
- struct OutputPropertyValue<true /*OutputExistence*/, IsMissing, cacheType, slotType>
- {
- static void impl(
- InlineCache* cache,
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext)
- {
- *propertyValue = IsMissing ? requestContext->GetLibrary()->GetFalse() : requestContext->GetLibrary()->GetTrue();
- Assert(!JavascriptOperators::HasProperty(propertyObject, propertyId) == IsMissing);
- }
- };
- template<bool IsMissing, SlotType slotType>
- struct OutputPropertyValue<false /*OutputExistence*/, IsMissing, CacheType::CacheType_Getter, slotType>
- {
- static void impl(
- InlineCache* cache,
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext)
- {
- Assert(cache->u.accessor.flags & InlineCacheGetterFlag);
- RecyclableObject * function;
- if (cache->u.accessor.isOnProto)
- {
- function = RecyclableObject::UnsafeFromVar(cache->GetPropertyValue<slotType>(cache->u.accessor.object, cache->u.accessor.slotIndex));
- }
- else
- {
- function = RecyclableObject::UnsafeFromVar(cache->GetPropertyValue<slotType>(DynamicObject::UnsafeFromVar(propertyObject), cache->u.accessor.slotIndex));
- }
- *propertyValue = JavascriptOperators::CallGetter(function, instance, requestContext);
- // Can't assert because the getter could have a side effect
- #ifdef CHKGETTER
- Assert(JavascriptOperators::Equal(*propertyValue, JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext), requestContext));
- #endif
- }
- };
- template<bool IsMissing, CacheType cacheType, SlotType slotType>
- struct OutputPropertyValue<false /*OutputExistence*/, IsMissing, cacheType, slotType>
- {
- static void impl(
- InlineCache* cache,
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext)
- {
- *propertyValue = InlineCache::GetPropertyValue<slotType>(cache->GetSourceObject<cacheType>(propertyObject), cache->GetSlotIndex<cacheType>());
- #if DBG
- Var slowPathValue = JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext);
- Var rootObjectValue = nullptr;
- if (RootObjectBase::Is(propertyObject))
- {
- rootObjectValue = JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext);
- }
- Assert(*propertyValue == slowPathValue ||
- (RootObjectBase::Is(propertyObject) && *propertyValue == rootObjectValue) ||
- // In some cases, such as CustomExternalObject, if implicit calls are disabled GetPropertyQuery may return null. See CustomExternalObject::GetPropertyQuery for an example.
- (slowPathValue == requestContext->GetLibrary()->GetNull() && requestContext->GetThreadContext()->IsDisableImplicitCall() && propertyObject->GetType()->IsExternal()));
- #endif
- }
- };
- };
- #if defined(TARGET_32)
- CompileAssert(sizeof(InlineCache) == 0x10);
- #else
- CompileAssert(sizeof(InlineCache) == 0x20);
- #endif
- CompileAssert(sizeof(InlineCache) == sizeof(InlineCacheAllocator::CacheLayout));
- CompileAssert(offsetof(InlineCache, invalidationListSlotPtr) == offsetof(InlineCacheAllocator::CacheLayout, strongRef));
- class PolymorphicInlineCache : public FinalizableObject
- {
- DECLARE_RECYCLER_VERIFY_MARK_FRIEND()
- #ifdef INLINE_CACHE_STATS
- friend class Js::ScriptContext;
- #endif
- public:
- static const bool IsPolymorphic = true;
- protected:
- FieldNoBarrier(InlineCache *) inlineCaches;
- Field(uint16) size;
- Field(bool) ignoreForEquivalentObjTypeSpec;
- Field(bool) cloneForJitTimeUse;
- Field(int32) inlineCachesFillInfo;
- PolymorphicInlineCache(InlineCache * inlineCaches, uint16 size)
- : inlineCaches(inlineCaches), size(size), ignoreForEquivalentObjTypeSpec(false), cloneForJitTimeUse(true), inlineCachesFillInfo(0)
- {
- }
- public:
- bool CanAllocateBigger() { return GetSize() < MaxPolymorphicInlineCacheSize; }
- static uint16 GetNextSize(uint16 currentSize)
- {
- if (currentSize == MaxPolymorphicInlineCacheSize)
- {
- return 0;
- }
- else if (currentSize == MinPropertyStringInlineCacheSize)
- {
- CompileAssert(MinPropertyStringInlineCacheSize < MinPolymorphicInlineCacheSize);
- return MinPolymorphicInlineCacheSize;
- }
- else
- {
- Assert(currentSize >= MinPolymorphicInlineCacheSize && currentSize <= (MaxPolymorphicInlineCacheSize / 2));
- return currentSize * 2;
- }
- }
- template<bool isAccessor>
- bool HasDifferentType(const bool isProto, const Type * type, const Type * typeWithoutProperty) const;
- bool HasType_Flags(const Type * type) const;
- InlineCache * GetInlineCaches() const { return inlineCaches; }
- uint16 GetSize() const { return size; }
- bool GetIgnoreForEquivalentObjTypeSpec() const { return this->ignoreForEquivalentObjTypeSpec; }
- void SetIgnoreForEquivalentObjTypeSpec(bool value) { this->ignoreForEquivalentObjTypeSpec = value; }
- bool GetCloneForJitTimeUse() const { return this->cloneForJitTimeUse; }
- void SetCloneForJitTimeUse(bool value) { this->cloneForJitTimeUse = value; }
- uint32 GetInlineCachesFillInfo() { return this->inlineCachesFillInfo; }
- void UpdateInlineCachesFillInfo(uint32 index, bool set);
- bool IsFull();
- void Clear(Type * type);
- virtual void Dispose(bool isShutdown) override { };
- virtual void Mark(Recycler *recycler) override { AssertMsg(false, "Mark called on object that isn't TrackableObject"); }
- void CacheLocal(
- Type *const type,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- Type *const typeWithoutProperty,
- int requiredAuxSlotCapacity,
- ScriptContext *const requestContext);
- void CacheProto(
- DynamicObject *const prototypeObjectWithProperty,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- const bool isMissing,
- Type *const type,
- ScriptContext *const requestContext);
- void CacheAccessor(
- const bool isGetter,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- Type *const type,
- DynamicObject *const object,
- const bool isOnProto,
- ScriptContext *const requestContext);
- template<
- bool CheckLocal,
- bool CheckProto,
- bool CheckAccessor,
- bool CheckMissing,
- bool IsInlineCacheAvailable,
- bool ReturnOperationInfo,
- bool OutputExistence /*When set, propertyValue is true or false, representing whether the property exists on the instance not its actual value*/>
- bool TryGetProperty(
- Var const instance,
- RecyclableObject *const propertyObject,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo *const operationInfo,
- InlineCache *const inlineCacheToPopulate);
- template<
- bool CheckLocal,
- bool CheckLocalTypeWithoutProperty,
- bool CheckAccessor,
- bool ReturnOperationInfo,
- bool PopulateInlineCache>
- bool TrySetProperty(
- RecyclableObject *const object,
- const PropertyId propertyId,
- Var propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo *const operationInfo,
- InlineCache *const inlineCacheToPopulate,
- const PropertyOperationFlags propertyOperationFlags = PropertyOperation_None);
- bool PretendTryGetProperty(Type *const type, PropertyCacheOperationInfo * operationInfo);
- bool PretendTrySetProperty(Type *const type, Type *const oldType, PropertyCacheOperationInfo * operationInfo);
- void CopyTo(PropertyId propertyId, ScriptContext* scriptContext, PolymorphicInlineCache *const clone);
- #if DBG_DUMP
- void Dump();
- #endif
- uint GetInlineCacheIndexForType(const Type * type) const
- {
- return (((size_t)type) >> PolymorphicInlineCacheShift) & (GetSize() - 1);
- }
- #ifdef INLINE_CACHE_STATS
- virtual void PrintStats(InlineCacheData *data) const = 0;
- #endif
- virtual ScriptContext* GetScriptContext() const = 0;
- static uint32 GetOffsetOfSize() { return offsetof(Js::PolymorphicInlineCache, size); }
- static uint32 GetOffsetOfInlineCaches() { return offsetof(Js::PolymorphicInlineCache, inlineCaches); }
- private:
- uint GetNextInlineCacheIndex(uint index) const
- {
- if (++index == GetSize())
- {
- index = 0;
- }
- return index;
- }
- template<bool CheckLocal, bool CheckProto, bool CheckAccessor>
- void CloneInlineCacheToEmptySlotInCollision(Type *const type, uint index);
- #ifdef CLONE_INLINECACHE_TO_EMPTYSLOT
- template <typename TDelegate>
- bool CheckClonedInlineCache(uint inlineCacheIndex, TDelegate mapper);
- #endif
- #if INTRUSIVE_TESTTRACE_PolymorphicInlineCache
- uint GetEntryCount()
- {
- uint count = 0;
- for (uint i = 0; i < size; ++i)
- {
- if (!inlineCaches[i].IsEmpty())
- {
- count++;
- }
- }
- return count;
- }
- #endif
- };
- class FunctionBodyPolymorphicInlineCache sealed : public PolymorphicInlineCache
- {
- private:
- FunctionBody * functionBody;
- // DList chaining all polymorphic inline caches of a FunctionBody together.
- // Since PolymorphicInlineCache is a leaf object, these references do not keep
- // the polymorphic inline caches alive. When a PolymorphicInlineCache is finalized,
- // it removes itself from the list and deletes its inline cache array.
- // We maintain this linked list of polymorphic caches because when we allocate a larger cache,
- // the old one might still be used by some code on the stack. Consequently, we can't release
- // the inline cache array back to the arena allocator.
- FunctionBodyPolymorphicInlineCache * next;
- FunctionBodyPolymorphicInlineCache * prev;
- FunctionBodyPolymorphicInlineCache(InlineCache * inlineCaches, uint16 size, FunctionBody * functionBody)
- : PolymorphicInlineCache(inlineCaches, size), functionBody(functionBody), next(nullptr), prev(nullptr)
- {
- Assert((size == 0 && inlineCaches == nullptr) ||
- (inlineCaches != nullptr && size >= MinPolymorphicInlineCacheSize && size <= MaxPolymorphicInlineCacheSize));
- }
- public:
- static FunctionBodyPolymorphicInlineCache * New(uint16 size, FunctionBody * functionBody);
- #ifdef INLINE_CACHE_STATS
- virtual void PrintStats(InlineCacheData *data) const override;
- #endif
- virtual ScriptContext* GetScriptContext() const override;
- virtual void Finalize(bool isShutdown) override;
- };
- class ScriptContextPolymorphicInlineCache sealed : public PolymorphicInlineCache
- {
- private:
- Field(JavascriptLibrary*) javascriptLibrary;
- ScriptContextPolymorphicInlineCache(InlineCache * inlineCaches, uint16 size, JavascriptLibrary * javascriptLibrary)
- : PolymorphicInlineCache(inlineCaches, size), javascriptLibrary(javascriptLibrary)
- {
- Assert((size == 0 && inlineCaches == nullptr) ||
- (inlineCaches != nullptr && size >= MinPropertyStringInlineCacheSize && size <= MaxPolymorphicInlineCacheSize));
- }
- public:
- static ScriptContextPolymorphicInlineCache * New(uint16 size, JavascriptLibrary * javascriptLibrary);
- #ifdef INLINE_CACHE_STATS
- virtual void PrintStats(InlineCacheData *data) const override;
- #endif
- virtual ScriptContext* GetScriptContext() const override;
- virtual void Finalize(bool isShutdown) override;
- };
- // Caches the result of an instanceof operator over a type and a function
- struct IsInstInlineCache
- {
- Type * type; // The type of object operand an inline cache caches a result for
- JavascriptFunction * function; // The function operand an inline cache caches a result for
- JavascriptBoolean * result; // The result of doing (object instanceof function) where object->type == this->type
- IsInstInlineCache * next; // Used to link together caches that have the same function operand
- public:
- bool IsEmpty() const { return type == nullptr; }
- bool TryGetResult(Var instance, JavascriptFunction * function, JavascriptBoolean ** result);
- void Cache(Type * instanceType, JavascriptFunction * function, JavascriptBoolean * result, ScriptContext * scriptContext);
- void Unregister(ScriptContext * scriptContext);
- void Clear();
- static uint32 OffsetOfFunction();
- static uint32 OffsetOfResult();
- static uint32 OffsetOfType();
- private:
- void Set(Type * instanceType, JavascriptFunction * function, JavascriptBoolean * result);
- };
- // Two-entry Type-indexed circular cache
- // cache IsConcatSpreadable() result unless user-defined [@@isConcatSpreadable] exists
- class IsConcatSpreadableCache
- {
- Type *type0, *type1;
- int lastAccess;
- BOOL result0, result1;
- public:
- IsConcatSpreadableCache() :
- type0(nullptr),
- type1(nullptr),
- result0(FALSE),
- result1(FALSE),
- lastAccess(1)
- {
- }
- bool TryGetIsConcatSpreadable(Type *type, _Out_ BOOL *result)
- {
- Assert(type != nullptr);
- Assert(result != nullptr);
- *result = FALSE;
- if (type0 == type)
- {
- *result = result0;
- lastAccess = 0;
- return true;
- }
- if (type1 == type)
- {
- *result = result1;
- lastAccess = 1;
- return true;
- }
- return false;
- }
- void CacheIsConcatSpreadable(Type *type, BOOL result)
- {
- Assert(type != nullptr);
- if (lastAccess == 0)
- {
- type1 = type;
- result1 = result;
- lastAccess = 1;
- }
- else
- {
- type0 = type;
- result0 = result;
- lastAccess = 0;
- }
- }
- void Invalidate()
- {
- type0 = nullptr;
- type1 = nullptr;
- }
- };
- #if defined(TARGET_32)
- CompileAssert(sizeof(IsInstInlineCache) == 0x10);
- #else
- CompileAssert(sizeof(IsInstInlineCache) == 0x20);
- #endif
- }
|