| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- namespace Js
- {
- enum class CtorCacheGuardValues : intptr_t
- {
- TagFlag = 0x01,
- Invalid = 0x00,
- Special = TagFlag
- };
- ENUM_CLASS_HELPERS(CtorCacheGuardValues, intptr_t);
- #define MaxCachedSlotCount 65535
- struct ConstructorCache : public PropertyGuard
- {
- friend class JavascriptFunction;
- struct ContentStruct
- {
- Field(ScriptContext*) scriptContext;
- // In a pinch we could eliminate this and store type pending sharing in the type field as long
- // as the guard value flags fit below the object alignment boundary. However, this wouldn't
- // keep the type alive, so it would only work if we zeroed constructor caches before GC.
- Field(DynamicType*) pendingType;
- // We cache only types whose slotCount < 64K to ensure the slotCount field doesn't look like a pointer to the recycler.
- Field(int) slotCount;
- // This layout (i.e. one-byte bit fields first, then the one-byte updateAfterCtor, and then the two byte inlineSlotCount) is
- // chosen intentionally to make sure the whole four bytes never look like a pointer and create a false reference pinning something
- // in recycler heap. The isPopulated bit is always set when the cache holds any data - even if it got invalidated.
- Field(bool) isPopulated : 1;
- Field(bool) isPolymorphic : 1;
- Field(bool) typeUpdatePending : 1;
- Field(bool) ctorHasNoExplicitReturnValue : 1;
- Field(bool) skipDefaultNewObject : 1;
- // This field indicates that the type stored in this cache is the final type after constructor.
- Field(bool) typeIsFinal : 1;
- // This field indicates that the constructor cache has been invalidated due to a constructor's prototype property change.
- // We use this flag to determine if we should mark the cache as polymorphic and not attempt subsequent optimizations.
- // The cache may also be invalidated due to a guard invalidation resulting from some property change (e.g. in proto chain),
- // in which case we won't deem the cache polymorphic.
- Field(bool) hasPrototypeChanged : 1;
- Field(uint8) callCount;
- // Separate from the bit field below for convenient compare from the JIT-ed code. Doesn't currently increase the size.
- // If size becomes an issue, we could merge back into the bit field and use a TEST instead of CMP.
- Field(bool) updateAfterCtor;
- Field(int16) inlineSlotCount;
- };
- Field(ContentStruct) content;
- CompileAssert(static_cast<intptr_t>(CtorCacheGuardValues::Invalid) == static_cast<intptr_t>(NULL));
- static ConstructorCache DefaultInstance;
- public:
- ConstructorCache();
- ConstructorCache(ConstructorCache const * other);
- static size_t const GetOffsetOfGuardValue() { return PropertyGuard::GetOffsetOfValue(); }
- static size_t const GetSizeOfGuardValue() { return PropertyGuard::GetSizeOfValue(); }
- void Populate(DynamicType* type, ScriptContext* scriptContext, bool ctorHasNoExplicitReturnValue, bool updateAfterCtor);
- void PopulateForSkipDefaultNewObject(ScriptContext* scriptContext);
- bool TryUpdateAfterConstructor(DynamicType* type, ScriptContext* scriptContext);
- void UpdateInlineSlotCount();
- void EnableAfterTypeUpdate();
- intptr_t GetRawGuardValue() const { return __super::GetValue(); }
- DynamicType* GetGuardValueAsType() const
- {
- return reinterpret_cast<DynamicType*>((CtorCacheGuardValues)__super::GetValue() & ~CtorCacheGuardValues::TagFlag);
- }
- DynamicType* GetType() const
- {
- Assert(static_cast<intptr_t>((CtorCacheGuardValues)__super::GetValue() & CtorCacheGuardValues::TagFlag) == 0);
- return reinterpret_cast<DynamicType*>(__super::GetValue());
- }
- DynamicType* GetPendingType() const
- {
- return this->content.pendingType;
- }
- ScriptContext* GetScriptContext() const
- {
- return this->content.scriptContext;
- }
- int GetSlotCount() const
- {
- return this->content.slotCount;
- }
- int16 GetInlineSlotCount() const
- {
- return this->content.inlineSlotCount;
- }
- static bool IsDefault(const ConstructorCache* constructorCache)
- {
- return constructorCache == &ConstructorCache::DefaultInstance;
- }
- bool IsDefault() const
- {
- return IsDefault(this);
- }
- bool IsPopulated() const
- {
- Assert(IsConsistent());
- return this->content.isPopulated;
- }
- bool IsEmpty() const
- {
- Assert(IsConsistent());
- return !this->content.isPopulated;
- }
- bool IsPolymorphic() const
- {
- Assert(IsConsistent());
- return this->content.isPolymorphic;
- }
- bool GetSkipDefaultNewObject() const
- {
- return this->content.skipDefaultNewObject;
- }
- bool GetCtorHasNoExplicitReturnValue() const
- {
- return this->content.ctorHasNoExplicitReturnValue;
- }
- bool GetUpdateCacheAfterCtor() const
- {
- return this->content.updateAfterCtor;
- }
- bool GetTypeUpdatePending() const
- {
- return this->content.typeUpdatePending;
- }
- bool IsEnabled() const
- {
- return GetGuardValueAsType() != nullptr;
- }
- bool IsInvalidated() const
- {
- return (CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Invalid && this->content.isPopulated;
- }
- bool NeedsTypeUpdate() const
- {
- return (CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Special && this->content.typeUpdatePending;
- }
- uint8 CallCount() const
- {
- return content.callCount;
- }
- void IncCallCount()
- {
- ++content.callCount;
- Assert(content.callCount != 0);
- }
- bool NeedsUpdateAfterCtor() const
- {
- return this->content.updateAfterCtor;
- }
- bool IsNormal() const
- {
- return (CtorCacheGuardValues)__super::GetValue() != CtorCacheGuardValues::Invalid && static_cast<intptr_t>((CtorCacheGuardValues)__super::GetValue() & CtorCacheGuardValues::TagFlag) == 0;
- }
- bool SkipDefaultNewObject() const
- {
- return (CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Special && this->content.skipDefaultNewObject;
- }
- bool IsSetUpForJit() const
- {
- return GetRawGuardValue() != NULL && !IsPolymorphic() && !NeedsUpdateAfterCtor() && (IsNormal() || SkipDefaultNewObject());
- }
- void ClearUpdateAfterCtor()
- {
- Assert(IsConsistent());
- Assert(this->content.isPopulated);
- Assert(this->content.updateAfterCtor);
- this->content.updateAfterCtor = false;
- Assert(IsConsistent());
- }
- static ConstructorCache* EnsureValidInstance(ConstructorCache* currentCache, ScriptContext* scriptContext);
- const void* GetAddressOfGuardValue()
- {
- return reinterpret_cast<const void*>(__super::GetAddressOfValue());
- }
- static uint32 GetOffsetOfUpdateAfterCtor()
- {
- return offsetof(ConstructorCache, content.updateAfterCtor);
- }
- void InvalidateAsGuard()
- {
- Assert(!IsDefault(this));
- Invalidate();
- // Make sure we don't leak the types.
- Assert(this->content.pendingType == nullptr);
- Assert(IsInvalidated());
- Assert(IsConsistent());
- }
- #if DBG
- bool IsConsistent() const
- {
- return (CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Invalid ||
- (this->content.isPopulated && (
- ((CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Special && !this->content.updateAfterCtor && this->content.skipDefaultNewObject && !this->content.typeUpdatePending && this->content.slotCount == 0 && this->content.inlineSlotCount == 0 && this->content.pendingType == nullptr) ||
- ((CtorCacheGuardValues)__super::GetValue() == CtorCacheGuardValues::Special && !this->content.updateAfterCtor && this->content.typeUpdatePending && !this->content.skipDefaultNewObject && this->content.pendingType != nullptr) ||
- (((CtorCacheGuardValues)__super::GetValue() & CtorCacheGuardValues::TagFlag) == CtorCacheGuardValues::Invalid && !this->content.skipDefaultNewObject && !this->content.typeUpdatePending && this->content.pendingType == nullptr)));
- }
- #endif
- #if DBG_DUMP
- void Dump() const;
- #endif
- private:
- void InvalidateOnPrototypeChange();
- };
- }
|