| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- {
- template<
- bool CheckLocal,
- bool CheckProto,
- bool CheckAccessor,
- bool CheckMissing,
- bool CheckPolymorphicInlineCache,
- bool CheckTypePropertyCache,
- bool IsInlineCacheAvailable,
- bool IsPolymorphicInlineCacheAvailable,
- bool ReturnOperationInfo,
- bool OutputExistence /*When set, propertyValue represents whether the property exists on the instance, not its actual value*/>
- inline bool CacheOperators::TryGetProperty(
- Var const instance,
- const bool isRoot,
- RecyclableObject *const object,
- const PropertyId propertyId,
- Var *const propertyValue,
- ScriptContext *const requestContext,
- PropertyCacheOperationInfo * operationInfo,
- PropertyValueInfo *const propertyValueInfo)
- {
- CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
- Assert(!CheckTypePropertyCache || !isRoot);
- Assert(propertyValueInfo);
- Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
- Assert(IsPolymorphicInlineCacheAvailable == !!propertyValueInfo->GetPolymorphicInlineCache());
- Assert(!ReturnOperationInfo || operationInfo);
- if(CheckLocal || CheckProto || CheckAccessor || CheckMissing)
- {
- InlineCache *const inlineCache = IsInlineCacheAvailable ? propertyValueInfo->GetInlineCache() : nullptr;
- if(IsInlineCacheAvailable)
- {
- if (inlineCache->TryGetProperty<CheckLocal, CheckProto, CheckAccessor, CheckMissing, ReturnOperationInfo, OutputExistence>(
- instance,
- object,
- propertyId,
- propertyValue,
- requestContext,
- operationInfo))
- {
- return true;
- }
- if(ReturnOperationInfo)
- {
- operationInfo->isPolymorphic = inlineCache->HasDifferentType(object->GetType());
- }
- }
- else if(ReturnOperationInfo)
- {
- operationInfo->isPolymorphic = true;
- }
- if(CheckPolymorphicInlineCache)
- {
- Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
- PolymorphicInlineCache *const polymorphicInlineCache =
- IsPolymorphicInlineCacheAvailable
- ? propertyValueInfo->GetPolymorphicInlineCache()
- : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(
- propertyValueInfo->GetInlineCacheIndex());
- if ((IsPolymorphicInlineCacheAvailable || polymorphicInlineCache) &&
- polymorphicInlineCache->TryGetProperty<
- CheckLocal,
- CheckProto,
- CheckAccessor,
- CheckMissing,
- IsInlineCacheAvailable,
- ReturnOperationInfo,
- OutputExistence
- >(
- instance,
- object,
- propertyId,
- propertyValue,
- requestContext,
- operationInfo,
- inlineCache
- ))
- {
- return true;
- }
- }
- }
- if(!CheckTypePropertyCache)
- {
- return false;
- }
- TypePropertyCache *const typePropertyCache = object->GetType()->GetPropertyCache();
- if(!typePropertyCache ||
- !typePropertyCache->TryGetProperty<OutputExistence>(
- CheckMissing,
- object,
- propertyId,
- propertyValue,
- requestContext,
- ReturnOperationInfo ? operationInfo : nullptr,
- propertyValueInfo))
- {
- return false;
- }
- if(!ReturnOperationInfo || operationInfo->cacheType == CacheType_TypeProperty)
- {
- return true;
- }
- // The property access was cached in an inline cache. Get the proper property operation info.
- PretendTryGetProperty<IsInlineCacheAvailable, IsPolymorphicInlineCacheAvailable>(
- object->GetType(),
- operationInfo,
- propertyValueInfo);
- return true;
- }
- template<
- bool CheckLocal,
- bool CheckLocalTypeWithoutProperty,
- bool CheckAccessor,
- bool CheckPolymorphicInlineCache,
- bool CheckTypePropertyCache,
- bool IsInlineCacheAvailable,
- bool IsPolymorphicInlineCacheAvailable,
- bool ReturnOperationInfo>
- inline bool CacheOperators::TrySetProperty(
- RecyclableObject *const object,
- const bool isRoot,
- const PropertyId propertyId,
- Var propertyValue,
- ScriptContext *const requestContext,
- const PropertyOperationFlags propertyOperationFlags,
- PropertyCacheOperationInfo * operationInfo,
- PropertyValueInfo *const propertyValueInfo)
- {
- CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
- Assert(!CheckTypePropertyCache || !isRoot);
- Assert(propertyValueInfo);
- Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
- Assert(IsPolymorphicInlineCacheAvailable == !!propertyValueInfo->GetPolymorphicInlineCache());
- Assert(!ReturnOperationInfo || operationInfo);
- if(CheckLocal || CheckLocalTypeWithoutProperty || CheckAccessor)
- {
- InlineCache *const inlineCache = IsInlineCacheAvailable ? propertyValueInfo->GetInlineCache() : nullptr;
- if(IsInlineCacheAvailable)
- {
- if (inlineCache->TrySetProperty<CheckLocal, CheckLocalTypeWithoutProperty, CheckAccessor, ReturnOperationInfo>(
- object,
- propertyId,
- propertyValue,
- requestContext,
- operationInfo,
- propertyOperationFlags))
- {
- return true;
- }
- if(ReturnOperationInfo)
- {
- operationInfo->isPolymorphic = inlineCache->HasDifferentType(object->GetType());
- }
- }
- else if(ReturnOperationInfo)
- {
- operationInfo->isPolymorphic = true;
- }
- if(CheckPolymorphicInlineCache)
- {
- Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
- PolymorphicInlineCache *const polymorphicInlineCache =
- IsPolymorphicInlineCacheAvailable
- ? propertyValueInfo->GetPolymorphicInlineCache()
- : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(
- propertyValueInfo->GetInlineCacheIndex());
- if ((IsPolymorphicInlineCacheAvailable || polymorphicInlineCache) &&
- polymorphicInlineCache->TrySetProperty<
- CheckLocal,
- CheckLocalTypeWithoutProperty,
- CheckAccessor,
- IsInlineCacheAvailable,
- ReturnOperationInfo
- >(
- object,
- propertyId,
- propertyValue,
- requestContext,
- operationInfo,
- inlineCache,
- propertyOperationFlags
- ))
- {
- return true;
- }
- }
- }
- if(!CheckTypePropertyCache)
- {
- return false;
- }
- TypePropertyCache *const typePropertyCache = object->GetType()->GetPropertyCache();
- if(!typePropertyCache ||
- !typePropertyCache->TrySetProperty(
- object,
- propertyId,
- propertyValue,
- requestContext,
- ReturnOperationInfo ? operationInfo : nullptr,
- propertyValueInfo))
- {
- return false;
- }
- if(!ReturnOperationInfo || operationInfo->cacheType == CacheType_TypeProperty)
- {
- return true;
- }
- // The property access was cached in an inline cache. Get the proper property operation info.
- PretendTrySetProperty<IsInlineCacheAvailable, IsPolymorphicInlineCacheAvailable>(
- object->GetType(),
- object->GetType(),
- operationInfo,
- propertyValueInfo);
- return true;
- }
- template<
- bool IsInlineCacheAvailable,
- bool IsPolymorphicInlineCacheAvailable>
- inline void CacheOperators::PretendTryGetProperty(
- Type *const type,
- PropertyCacheOperationInfo *operationInfo,
- PropertyValueInfo *const propertyValueInfo)
- {
- CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
- Assert(propertyValueInfo);
- Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
- Assert(!IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetPolymorphicInlineCache());
- Assert(operationInfo);
- if (IsInlineCacheAvailable && propertyValueInfo->GetInlineCache()->PretendTryGetProperty(type, operationInfo))
- {
- return;
- }
- Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
- PolymorphicInlineCache *const polymorphicInlineCache =
- IsPolymorphicInlineCacheAvailable
- ? propertyValueInfo->GetPolymorphicInlineCache()
- : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(propertyValueInfo->GetInlineCacheIndex());
- if (IsPolymorphicInlineCacheAvailable || polymorphicInlineCache)
- {
- polymorphicInlineCache->PretendTryGetProperty(type, operationInfo);
- }
- }
- template<
- bool IsInlineCacheAvailable,
- bool IsPolymorphicInlineCacheAvailable>
- inline void CacheOperators::PretendTrySetProperty(
- Type *const type,
- Type *const oldType,
- PropertyCacheOperationInfo * operationInfo,
- PropertyValueInfo *const propertyValueInfo)
- {
- CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
- Assert(propertyValueInfo);
- Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
- Assert(!IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetPolymorphicInlineCache());
- Assert(operationInfo);
- if (IsInlineCacheAvailable && propertyValueInfo->GetInlineCache()->PretendTrySetProperty(type, oldType, operationInfo))
- {
- return;
- }
- Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
- PolymorphicInlineCache *const polymorphicInlineCache =
- IsPolymorphicInlineCacheAvailable
- ? propertyValueInfo->GetPolymorphicInlineCache()
- : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(propertyValueInfo->GetInlineCacheIndex());
- if (IsPolymorphicInlineCacheAvailable || polymorphicInlineCache)
- {
- polymorphicInlineCache->PretendTrySetProperty(type, oldType, operationInfo);
- }
- }
- template<
- bool IsAccessor,
- bool IsRead,
- bool IncludeTypePropertyCache>
- inline void CacheOperators::Cache(
- const bool isProto,
- DynamicObject *const objectWithProperty,
- const bool isRoot,
- Type *const type,
- Type *const typeWithoutProperty,
- const PropertyId propertyId,
- const PropertyIndex propertyIndex,
- const bool isInlineSlot,
- const bool isMissing,
- const int requiredAuxSlotCapacity,
- PropertyValueInfo *const info,
- ScriptContext *const requestContext)
- {
- CompileAssert(!IsAccessor || !IncludeTypePropertyCache);
- Assert(info);
- Assert(objectWithProperty);
- if(!IsAccessor)
- {
- if(!isProto)
- {
- Assert(type == objectWithProperty->GetType());
- }
- else
- {
- Assert(IsRead);
- Assert(type != objectWithProperty->GetType());
- }
- }
- else
- {
- Assert(!isRoot); // could still be root object, but the parameter will be false and shouldn't be used for accessors
- Assert(!typeWithoutProperty);
- Assert(requiredAuxSlotCapacity == 0);
- }
- if(IsRead)
- {
- Assert(!typeWithoutProperty);
- Assert(requiredAuxSlotCapacity == 0);
- Assert(CanCachePropertyRead(objectWithProperty, requestContext));
- if(!IsAccessor && isProto && PropertyValueInfo::PrototypeCacheDisabled(info))
- {
- return;
- }
- // Before allowing proxies to cache, we would need to solve various issues (see JavascriptProxy::GetPropertyQuery).
- Assert(!JavascriptProxy::Is(objectWithProperty));
- }
- else
- {
- Assert(CanCachePropertyWrite(objectWithProperty, requestContext));
- // TODO(ianhall): the following assert would let global const properties slip through when they shadow
- // a global property. Reason being DictionaryTypeHandler::IsWritable cannot tell if it should check
- // the global property or the global let/const. Fix this by updating IsWritable to recognize isRoot.
- // Built-in Function.prototype properties 'length', 'arguments', and 'caller' are special cases.
- Assert(
- objectWithProperty->IsWritable(propertyId) ||
- (isRoot && RootObjectBase::FromVar(objectWithProperty)->IsLetConstGlobal(propertyId)) ||
- JavascriptFunction::IsBuiltinProperty(objectWithProperty, propertyId));
- }
- const bool includeTypePropertyCache =
- IncludeTypePropertyCache &&
- !isRoot &&
- (info->GetFunctionBody()
- ? !PHASE_OFF(Js::TypePropertyCachePhase, info->GetFunctionBody())
- : !PHASE_OFF1(Js::TypePropertyCachePhase)
- );
- bool createTypePropertyCache = false;
- // Side-effects may have changed the cache, so make sure the info has the latest.
- info->UpdatePolymorphicInlineCache(IsRead);
- PolymorphicInlineCache *polymorphicInlineCache = info->GetPolymorphicInlineCache();
- if(!polymorphicInlineCache && info->GetFunctionBody())
- {
- polymorphicInlineCache = info->GetFunctionBody()->GetPolymorphicInlineCache(info->GetInlineCacheIndex());
- }
- InlineCache *const inlineCache = info->GetInlineCache();
- if(inlineCache)
- {
- const bool tryCreatePolymorphicInlineCache = !polymorphicInlineCache && info->GetFunctionBody();
- if((includeTypePropertyCache || tryCreatePolymorphicInlineCache) &&
- inlineCache->HasDifferentType<IsAccessor>(isProto, type, typeWithoutProperty))
- {
- if(tryCreatePolymorphicInlineCache)
- {
- polymorphicInlineCache =
- info->GetFunctionBody()->CreateNewPolymorphicInlineCache(
- info->GetInlineCacheIndex(),
- propertyId,
- inlineCache);
- }
- if(includeTypePropertyCache)
- {
- createTypePropertyCache = true;
- }
- }
- if(!IsAccessor)
- {
- if(!isProto)
- {
- inlineCache->CacheLocal(
- type,
- propertyId,
- propertyIndex,
- isInlineSlot,
- typeWithoutProperty,
- requiredAuxSlotCapacity,
- requestContext);
- }
- else
- {
- inlineCache->CacheProto(
- objectWithProperty,
- propertyId,
- propertyIndex,
- isInlineSlot,
- isMissing,
- type,
- requestContext);
- }
- }
- else
- {
- inlineCache->CacheAccessor(
- IsRead,
- propertyId,
- propertyIndex,
- isInlineSlot,
- type,
- objectWithProperty,
- isProto,
- requestContext);
- }
- }
- if(polymorphicInlineCache)
- {
- // Don't resize a polymorphic inline cache from full JIT because it currently doesn't rejit to use the new
- // polymorphic inline cache. Once resized, bailouts would populate only the new set of caches and full JIT would
- // continue to use to old set of caches.
- Assert(!info->AllowResizingPolymorphicInlineCache() || info->GetFunctionBody() || info->GetPropertyRecordUsageCache());
- if(((includeTypePropertyCache && !createTypePropertyCache) || info->AllowResizingPolymorphicInlineCache()) &&
- polymorphicInlineCache->HasDifferentType<IsAccessor>(isProto, type, typeWithoutProperty))
- {
- if(info->AllowResizingPolymorphicInlineCache() && polymorphicInlineCache->CanAllocateBigger())
- {
- if (info->GetFunctionBody())
- {
- Assert(polymorphicInlineCache == info->GetFunctionBody()->GetPolymorphicInlineCache(info->GetInlineCacheIndex()));
- polymorphicInlineCache =
- info->GetFunctionBody()->CreateBiggerPolymorphicInlineCache(
- info->GetInlineCacheIndex(),
- propertyId);
- }
- else
- {
- Assert(!info->GetFunctionBody());
- Assert(polymorphicInlineCache == (IsRead ? info->GetPropertyRecordUsageCache()->GetLdElemInlineCache() : info->GetPropertyRecordUsageCache()->GetStElemInlineCache()));
- polymorphicInlineCache = info->GetPropertyRecordUsageCache()->CreateBiggerPolymorphicInlineCache(IsRead);
- }
- }
- if(includeTypePropertyCache)
- {
- createTypePropertyCache = true;
- }
- }
- if(!IsAccessor)
- {
- if(!isProto)
- {
- polymorphicInlineCache->CacheLocal(
- type,
- propertyId,
- propertyIndex,
- isInlineSlot,
- typeWithoutProperty,
- requiredAuxSlotCapacity,
- requestContext);
- }
- else
- {
- polymorphicInlineCache->CacheProto(
- objectWithProperty,
- propertyId,
- propertyIndex,
- isInlineSlot,
- isMissing,
- type,
- requestContext);
- }
- }
- else
- {
- polymorphicInlineCache->CacheAccessor(
- IsRead,
- propertyId,
- propertyIndex,
- isInlineSlot,
- type,
- objectWithProperty,
- isProto,
- requestContext);
- }
- }
- if(!includeTypePropertyCache)
- {
- return;
- }
- Assert(!IsAccessor);
- TypePropertyCache *typePropertyCache = type->GetPropertyCache();
- if(!typePropertyCache)
- {
- if(!createTypePropertyCache)
- {
- return;
- }
- typePropertyCache = type->CreatePropertyCache();
- }
- if(isProto)
- {
- typePropertyCache->Cache(
- propertyId,
- propertyIndex,
- isInlineSlot,
- info->IsWritable() && info->IsStoreFieldCacheEnabled(),
- isMissing,
- objectWithProperty,
- type);
- typePropertyCache = objectWithProperty->GetType()->GetPropertyCache();
- if(!typePropertyCache)
- {
- return;
- }
- }
- typePropertyCache->Cache(
- propertyId,
- propertyIndex,
- isInlineSlot,
- info->IsWritable() && info->IsStoreFieldCacheEnabled());
- }
- }
|