<commit_before>//-------------------------------------------------------------------------------------------------------
// 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 ReturnOperationInfo>
    bool InlineCache::TryGetProperty(
        Var const instance,
        RecyclableObject *const propertyObject,
        const PropertyId propertyId,
        Var *const propertyValue,
        ScriptContext *const requestContext,
        PropertyCacheOperationInfo *const operationInfo)
    {
        CompileAssert(CheckLocal || CheckProto || CheckAccessor);
        Assert(!ReturnOperationInfo || operationInfo);
        CompileAssert(!ReturnOperationInfo || (CheckLocal && CheckProto && CheckAccessor));
        Assert(instance);
        Assert(propertyObject);
        Assert(propertyId != Constants::NoProperty);
        Assert(propertyValue);
        Assert(requestContext);
        DebugOnly(VerifyRegistrationForInvalidation(this, requestContext, propertyId));

        Type *const type = propertyObject->GetType();

        if (CheckLocal && type == u.local.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = DynamicObject::FromVar(propertyObject)->GetInlineSlot(u.local.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Local;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckLocal && TypeWithAuxSlotTag(type) == u.local.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = DynamicObject::FromVar(propertyObject)->GetAuxSlot(u.local.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Local;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckProto && type == u.proto.type && !this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetInlineSlot(u.proto.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckProto && TypeWithAuxSlotTag(type) == u.proto.type && !this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetAuxSlot(u.proto.slotIndex);
            // TODO: This assert often results in Assert(RootObjectBase::Is(object)) inside GetRootProperty, which is misleading
            // when the problem is that GetProperty returned a different value than propertyValue. Consider reworking it here and elsewhere.
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckAccessor && type == u.accessor.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            Assert(u.accessor.flags & InlineCacheGetterFlag);

            RecyclableObject *const function = RecyclableObject::FromVar(u.accessor.object->GetInlineSlot(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
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Getter;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckAccessor && TypeWithAuxSlotTag(type) == u.accessor.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            Assert(u.accessor.flags & InlineCacheGetterFlag);

            RecyclableObject *const function = RecyclableObject::FromVar(u.accessor.object->GetAuxSlot(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
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Getter;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckMissing && type == u.proto.type && this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetInlineSlot(u.proto.slotIndex);
            // TODO: This assert often results in Assert(RootObjectBase::Is(object)) inside GetRootProperty, which is misleading
            // when the problem is that GetProperty returned a different value than propertyValue. Consider reworking it here and elsewhere.
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));

#ifdef MISSING_PROPERTY_STATS
            if (PHASE_STATS1(MissingPropertyCachePhase))
            {
                requestContext->RecordMissingPropertyHit();
            }
#endif

            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckMissing && TypeWithAuxSlotTag(type) == u.proto.type && this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetAuxSlot(u.proto.slotIndex);
            // TODO: This assert often results in Assert(RootObjectBase::Is(object)) inside GetRootProperty, which is misleading
            // when the problem is that GetProperty returned a different value than propertyValue. Consider reworking it here and elsewhere.
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext));

#ifdef MISSING_PROPERTY_STATS
            if (PHASE_STATS1(MissingPropertyCachePhase))
            {
                requestContext->RecordMissingPropertyHit();
            }
#endif

            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        return false;
    }

    template<
        bool CheckLocal,
        bool CheckLocalTypeWithoutProperty,
        bool CheckAccessor,
        bool ReturnOperationInfo>
    bool InlineCache::TrySetProperty(
        RecyclableObject *const object,
        const PropertyId propertyId,<commit_msg>Prevent firing of a misleading assert, calling GetRootProperty without verifying that the instance is a root object. (Addresses a TODO in the source.)<commit_after>//-------------------------------------------------------------------------------------------------------
// 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 ReturnOperationInfo>
    bool InlineCache::TryGetProperty(
        Var const instance,
        RecyclableObject *const propertyObject,
        const PropertyId propertyId,
        Var *const propertyValue,
        ScriptContext *const requestContext,
        PropertyCacheOperationInfo *const operationInfo)
    {
        CompileAssert(CheckLocal || CheckProto || CheckAccessor);
        Assert(!ReturnOperationInfo || operationInfo);
        CompileAssert(!ReturnOperationInfo || (CheckLocal && CheckProto && CheckAccessor));
        Assert(instance);
        Assert(propertyObject);
        Assert(propertyId != Constants::NoProperty);
        Assert(propertyValue);
        Assert(requestContext);
        DebugOnly(VerifyRegistrationForInvalidation(this, requestContext, propertyId));

        Type *const type = propertyObject->GetType();

        if (CheckLocal && type == u.local.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = DynamicObject::FromVar(propertyObject)->GetInlineSlot(u.local.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Local;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckLocal && TypeWithAuxSlotTag(type) == u.local.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = DynamicObject::FromVar(propertyObject)->GetAuxSlot(u.local.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Local;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckProto && type == u.proto.type && !this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetInlineSlot(u.proto.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckProto && TypeWithAuxSlotTag(type) == u.proto.type && !this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetAuxSlot(u.proto.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckAccessor && type == u.accessor.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            Assert(u.accessor.flags & InlineCacheGetterFlag);

            RecyclableObject *const function = RecyclableObject::FromVar(u.accessor.object->GetInlineSlot(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
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Getter;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckAccessor && TypeWithAuxSlotTag(type) == u.accessor.type)
        {
            Assert(propertyObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            Assert(u.accessor.flags & InlineCacheGetterFlag);

            RecyclableObject *const function = RecyclableObject::FromVar(u.accessor.object->GetAuxSlot(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
            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Getter;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        if (CheckMissing && type == u.proto.type && this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetInlineSlot(u.proto.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));

#ifdef MISSING_PROPERTY_STATS
            if (PHASE_STATS1(MissingPropertyCachePhase))
            {
                requestContext->RecordMissingPropertyHit();
            }
#endif

            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Inline;
            }
            return true;
        }

        if (CheckMissing && TypeWithAuxSlotTag(type) == u.proto.type && this->u.proto.isMissing)
        {
            Assert(u.proto.prototypeObject->GetScriptContext() == requestContext); // we never cache a type from another script context
            *propertyValue = u.proto.prototypeObject->GetAuxSlot(u.proto.slotIndex);
            Assert(*propertyValue == JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext) ||
                (RootObjectBase::Is(propertyObject) && *propertyValue == JavascriptOperators::GetRootProperty(propertyObject, propertyId, requestContext)));

#ifdef MISSING_PROPERTY_STATS
            if (PHASE_STATS1(MissingPropertyCachePhase))
            {
                requestContext->RecordMissingPropertyHit();
            }
#endif

            if (ReturnOperationInfo)
            {
                operationInfo->cacheType = CacheType_Proto;
                operationInfo->slotType = SlotType_Aux;
            }
            return true;
        }

        return false;
    }

    template<
        bool CheckLocal,
        bool CheckLocalTypeWithoutProperty,
        bool CheckAccessor,
        bool ReturnOperationInfo>
    bool InlineCache::TrySetProperty(
        RecyclableObject *const object,
        const PropertyId propertyId,
{'fraction_non_alphanumeric': 0.11068681468550542, 'fraction_numerical': 0.00021820959031149418, 'mean_word_length': 2.4413365871972967, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6327649', 'n_tokens_mistral': 4360, 'n_tokens_neox': 4222, 'n_words': 947}