14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/ic/ic_runtime.h"
174514f5e3Sopenharmony_ci#include "ecmascript/ic/ic_handler.h"
184514f5e3Sopenharmony_ci#include "ecmascript/interpreter/interpreter.h"
194514f5e3Sopenharmony_ci#include "ecmascript/interpreter/slow_runtime_stub.h"
204514f5e3Sopenharmony_ci#include "ecmascript/js_primitive_ref.h"
214514f5e3Sopenharmony_ci#include "ecmascript/shared_objects/js_shared_array.h"
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_cinamespace panda::ecmascript {
244514f5e3Sopenharmony_ci#define TRACE_IC 0  // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_civoid ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
274514f5e3Sopenharmony_ci                                  JSHandle<JSTaggedValue> receiver)
284514f5e3Sopenharmony_ci{
294514f5e3Sopenharmony_ci    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
304514f5e3Sopenharmony_ci        return;
314514f5e3Sopenharmony_ci    }
324514f5e3Sopenharmony_ci    if (IsNamedIC(GetICKind())) {
334514f5e3Sopenharmony_ci        key = JSHandle<JSTaggedValue>();
344514f5e3Sopenharmony_ci    }
354514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handlerValue;
364514f5e3Sopenharmony_ci    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
374514f5e3Sopenharmony_ci    JSHandle<JSHClass> originhclass;
384514f5e3Sopenharmony_ci    if (receiver->IsNumber()) {
394514f5e3Sopenharmony_ci        receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, receiver));
404514f5e3Sopenharmony_ci    } else if (receiver->IsString()) {
414514f5e3Sopenharmony_ci        originhclass = JSHandle<JSHClass>(thread_, receiver->GetTaggedObject()->GetClass());
424514f5e3Sopenharmony_ci        receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, receiver));
434514f5e3Sopenharmony_ci    }
444514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
454514f5e3Sopenharmony_ci    // When a transition occurs without the shadow property, AOT does not trigger the
464514f5e3Sopenharmony_ci    // notifyprototypechange behavior, so for the case where the property does not
474514f5e3Sopenharmony_ci    // exist and the Hclass is AOT, IC needs to be abandoned.
484514f5e3Sopenharmony_ci    if (hclass->IsTS() && !op.IsFound()) {
494514f5e3Sopenharmony_ci        return;
504514f5e3Sopenharmony_ci    }
514514f5e3Sopenharmony_ci    if (op.IsElement()) {
524514f5e3Sopenharmony_ci        if (!op.IsFound() && hclass->IsDictionaryElement()) {
534514f5e3Sopenharmony_ci            return;
544514f5e3Sopenharmony_ci        }
554514f5e3Sopenharmony_ci        handlerValue = LoadHandler::LoadElement(thread_, op);
564514f5e3Sopenharmony_ci    } else {
574514f5e3Sopenharmony_ci        if (!op.IsFound()) {
584514f5e3Sopenharmony_ci            JSTaggedValue proto = hclass->GetPrototype();
594514f5e3Sopenharmony_ci            if (!proto.IsECMAObject()) {
604514f5e3Sopenharmony_ci                handlerValue = LoadHandler::LoadProperty(thread_, op);
614514f5e3Sopenharmony_ci            } else {
624514f5e3Sopenharmony_ci                handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
634514f5e3Sopenharmony_ci            }
644514f5e3Sopenharmony_ci        } else if (!op.IsOnPrototype()) {
654514f5e3Sopenharmony_ci            handlerValue = LoadHandler::LoadProperty(thread_, op);
664514f5e3Sopenharmony_ci        } else {
674514f5e3Sopenharmony_ci            // do not support global prototype ic
684514f5e3Sopenharmony_ci            if (IsGlobalLoadIC(GetICKind())) {
694514f5e3Sopenharmony_ci                return;
704514f5e3Sopenharmony_ci            }
714514f5e3Sopenharmony_ci            handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
724514f5e3Sopenharmony_ci        }
734514f5e3Sopenharmony_ci    }
744514f5e3Sopenharmony_ci
754514f5e3Sopenharmony_ci    if (!originhclass.GetTaggedValue().IsUndefined()) {
764514f5e3Sopenharmony_ci        hclass = originhclass;
774514f5e3Sopenharmony_ci    }
784514f5e3Sopenharmony_ci    if (key.IsEmpty()) {
794514f5e3Sopenharmony_ci        icAccessor_.AddHandlerWithoutKey(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
804514f5e3Sopenharmony_ci    } else if (op.IsElement()) {
814514f5e3Sopenharmony_ci        // do not support global element ic
824514f5e3Sopenharmony_ci        if (IsGlobalLoadIC(GetICKind())) {
834514f5e3Sopenharmony_ci            return;
844514f5e3Sopenharmony_ci        }
854514f5e3Sopenharmony_ci        icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
864514f5e3Sopenharmony_ci    } else {
874514f5e3Sopenharmony_ci        icAccessor_.AddHandlerWithKey(key, JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
884514f5e3Sopenharmony_ci    }
894514f5e3Sopenharmony_ci}
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_civoid ICRuntime::UpdateLoadStringHandler(JSHandle<JSTaggedValue> receiver)
924514f5e3Sopenharmony_ci{
934514f5e3Sopenharmony_ci    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
944514f5e3Sopenharmony_ci        return;
954514f5e3Sopenharmony_ci    }
964514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handlerValue = LoadHandler::LoadStringElement(thread_);
974514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
984514f5e3Sopenharmony_ci    icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
994514f5e3Sopenharmony_ci}
1004514f5e3Sopenharmony_ci
1014514f5e3Sopenharmony_civoid ICRuntime::UpdateTypedArrayHandler(JSHandle<JSTaggedValue> receiver)
1024514f5e3Sopenharmony_ci{
1034514f5e3Sopenharmony_ci    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
1044514f5e3Sopenharmony_ci        return;
1054514f5e3Sopenharmony_ci    }
1064514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handlerValue =
1074514f5e3Sopenharmony_ci        LoadHandler::LoadTypedArrayElement(thread_, JSHandle<JSTypedArray>(receiver));
1084514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
1094514f5e3Sopenharmony_ci    icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
1104514f5e3Sopenharmony_ci}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_civoid ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
1134514f5e3Sopenharmony_ci                                   JSHandle<JSTaggedValue> receiver)
1144514f5e3Sopenharmony_ci{
1154514f5e3Sopenharmony_ci    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
1164514f5e3Sopenharmony_ci        return;
1174514f5e3Sopenharmony_ci    }
1184514f5e3Sopenharmony_ci    if (IsNamedIC(GetICKind())) {
1194514f5e3Sopenharmony_ci        key = JSHandle<JSTaggedValue>();
1204514f5e3Sopenharmony_ci    }
1214514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handlerValue;
1224514f5e3Sopenharmony_ci    ASSERT(op.IsFound());
1234514f5e3Sopenharmony_ci
1244514f5e3Sopenharmony_ci    if (op.IsTransition()) {
1254514f5e3Sopenharmony_ci        if (op.IsOnPrototype()) {
1264514f5e3Sopenharmony_ci            JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
1274514f5e3Sopenharmony_ci            handlerValue = TransWithProtoHandler::StoreTransition(thread_, op, hclass);
1284514f5e3Sopenharmony_ci        } else {
1294514f5e3Sopenharmony_ci            handlerValue = TransitionHandler::StoreTransition(thread_, op);
1304514f5e3Sopenharmony_ci        }
1314514f5e3Sopenharmony_ci    } else if (op.IsOnPrototype()) {
1324514f5e3Sopenharmony_ci        // do not support global prototype ic
1334514f5e3Sopenharmony_ci        if (IsGlobalStoreIC(GetICKind())) {
1344514f5e3Sopenharmony_ci            return;
1354514f5e3Sopenharmony_ci        }
1364514f5e3Sopenharmony_ci        JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
1374514f5e3Sopenharmony_ci        handlerValue = PrototypeHandler::StorePrototype(thread_, op, hclass);
1384514f5e3Sopenharmony_ci    } else {
1394514f5e3Sopenharmony_ci        handlerValue = StoreHandler::StoreProperty(thread_, op);
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    if (key.IsEmpty()) {
1434514f5e3Sopenharmony_ci        icAccessor_.AddHandlerWithoutKey(receiverHClass_, handlerValue);
1444514f5e3Sopenharmony_ci    } else if (op.IsElement()) {
1454514f5e3Sopenharmony_ci        // do not support global element ic
1464514f5e3Sopenharmony_ci        if (IsGlobalStoreIC(GetICKind())) {
1474514f5e3Sopenharmony_ci            return;
1484514f5e3Sopenharmony_ci        }
1494514f5e3Sopenharmony_ci        icAccessor_.AddElementHandler(receiverHClass_, handlerValue);
1504514f5e3Sopenharmony_ci    } else {
1514514f5e3Sopenharmony_ci        icAccessor_.AddHandlerWithKey(key, receiverHClass_, handlerValue);
1524514f5e3Sopenharmony_ci    }
1534514f5e3Sopenharmony_ci}
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_civoid ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
1564514f5e3Sopenharmony_ci                        [[maybe_unused]] JSHandle<JSTaggedValue> key) const
1574514f5e3Sopenharmony_ci{
1584514f5e3Sopenharmony_ci#if TRACE_IC
1594514f5e3Sopenharmony_ci    auto kind = ICKindToString(GetICKind());
1604514f5e3Sopenharmony_ci    auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
1614514f5e3Sopenharmony_ci    if (key->IsString()) {
1624514f5e3Sopenharmony_ci        auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
1634514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << kind << " miss key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
1644514f5e3Sopenharmony_ci                            << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
1654514f5e3Sopenharmony_ci                            << ", state is " << state;
1664514f5e3Sopenharmony_ci    } else {
1674514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << kind << " miss " << ", state is "
1684514f5e3Sopenharmony_ci                            << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
1694514f5e3Sopenharmony_ci                            << state;
1704514f5e3Sopenharmony_ci    }
1714514f5e3Sopenharmony_ci#endif
1724514f5e3Sopenharmony_ci}
1734514f5e3Sopenharmony_ci
1744514f5e3Sopenharmony_ciJSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
1754514f5e3Sopenharmony_ci{
1764514f5e3Sopenharmony_ci    JSTaggedValue::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
1774514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
1784514f5e3Sopenharmony_ci
1794514f5e3Sopenharmony_ci    if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) && !receiver->IsString()) {
1804514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
1814514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
1824514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
1834514f5e3Sopenharmony_ci        return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
1844514f5e3Sopenharmony_ci    }
1854514f5e3Sopenharmony_ci    if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
1864514f5e3Sopenharmony_ci        return LoadTypedArrayValueMiss(receiver, key);
1874514f5e3Sopenharmony_ci    }
1884514f5e3Sopenharmony_ci    // fixme(hzzhouzebin) Open IC for SharedArray later.
1894514f5e3Sopenharmony_ci    if (receiver->IsJSSharedArray()) {
1904514f5e3Sopenharmony_ci        return JSSharedArray::GetProperty(thread_, receiver, key, SCheckMode::CHECK).GetValue().GetTaggedValue();
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci    ObjectOperator op(GetThread(), receiver, key);
1934514f5e3Sopenharmony_ci    auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
1944514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
1954514f5e3Sopenharmony_ci
1964514f5e3Sopenharmony_ci    if (receiver->IsString()) {
1974514f5e3Sopenharmony_ci         // do not cache element
1984514f5e3Sopenharmony_ci        if (!op.IsFastMode()) {
1994514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
2004514f5e3Sopenharmony_ci            return result.GetTaggedValue();
2014514f5e3Sopenharmony_ci        }
2024514f5e3Sopenharmony_ci        UpdateLoadStringHandler(receiver);
2034514f5e3Sopenharmony_ci    } else {
2044514f5e3Sopenharmony_ci        if (op.GetValue().IsAccessor()) {
2054514f5e3Sopenharmony_ci            op = ObjectOperator(GetThread(), receiver, key);
2064514f5e3Sopenharmony_ci        }
2074514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
2084514f5e3Sopenharmony_ci        // ic-switch
2094514f5e3Sopenharmony_ci        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
2104514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
2114514f5e3Sopenharmony_ci            return result.GetTaggedValue();
2124514f5e3Sopenharmony_ci        }
2134514f5e3Sopenharmony_ci        TraceIC(receiver, key);
2144514f5e3Sopenharmony_ci        // do not cache element
2154514f5e3Sopenharmony_ci        if (!op.IsFastMode()) {
2164514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
2174514f5e3Sopenharmony_ci            return result.GetTaggedValue();
2184514f5e3Sopenharmony_ci        }
2194514f5e3Sopenharmony_ci        UpdateLoadHandler(op, key, receiver);
2204514f5e3Sopenharmony_ci    }
2214514f5e3Sopenharmony_ci
2224514f5e3Sopenharmony_ci    return result.GetTaggedValue();
2234514f5e3Sopenharmony_ci}
2244514f5e3Sopenharmony_ci
2254514f5e3Sopenharmony_ciJSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
2264514f5e3Sopenharmony_ci{
2274514f5e3Sopenharmony_ci    if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) &&
2284514f5e3Sopenharmony_ci         !receiver->IsString() && !receiver->IsNumber()) {
2294514f5e3Sopenharmony_ci        return LoadOrdinaryGet(receiver, key);
2304514f5e3Sopenharmony_ci    }
2314514f5e3Sopenharmony_ci
2324514f5e3Sopenharmony_ci    ICKind kind = GetICKind();
2334514f5e3Sopenharmony_ci    // global variable find from global record firstly
2344514f5e3Sopenharmony_ci    if (kind == ICKind::NamedGlobalLoadIC || kind == ICKind::NamedGlobalTryLoadIC) {
2354514f5e3Sopenharmony_ci        JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
2364514f5e3Sopenharmony_ci        if (!box.IsUndefined()) {
2374514f5e3Sopenharmony_ci            ASSERT(box.IsPropertyBox());
2384514f5e3Sopenharmony_ci            if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
2394514f5e3Sopenharmony_ci                icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
2404514f5e3Sopenharmony_ci            }
2414514f5e3Sopenharmony_ci            return PropertyBox::Cast(box.GetTaggedObject())->GetValue();
2424514f5e3Sopenharmony_ci        }
2434514f5e3Sopenharmony_ci    }
2444514f5e3Sopenharmony_ci
2454514f5e3Sopenharmony_ci    if (key->IsJSFunction()) { // key is a private getter
2464514f5e3Sopenharmony_ci        return CallPrivateGetter(receiver, key);
2474514f5e3Sopenharmony_ci    }
2484514f5e3Sopenharmony_ci
2494514f5e3Sopenharmony_ci    if (key->IsSymbol() && JSSymbol::Cast(key->GetTaggedObject())->IsPrivate()) {
2504514f5e3Sopenharmony_ci        PropertyDescriptor desc(thread_);
2514514f5e3Sopenharmony_ci        if (!JSTaggedValue::IsPropertyKey(key) ||
2524514f5e3Sopenharmony_ci            !JSTaggedValue::GetOwnProperty(thread_, receiver, key, desc)) {
2534514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(thread_, "invalid or cannot find private key", JSTaggedValue::Exception());
2544514f5e3Sopenharmony_ci        }
2554514f5e3Sopenharmony_ci    }
2564514f5e3Sopenharmony_ci
2574514f5e3Sopenharmony_ci    ObjectOperator op(GetThread(), receiver, key);
2584514f5e3Sopenharmony_ci    auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
2594514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
2604514f5e3Sopenharmony_ci    if (op.GetValue().IsAccessor()) {
2614514f5e3Sopenharmony_ci        op = ObjectOperator(GetThread(), receiver, key);
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci    if (!op.IsFound() && kind == ICKind::NamedGlobalTryLoadIC) {
2644514f5e3Sopenharmony_ci        return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
2674514f5e3Sopenharmony_ci    // ic-switch
2684514f5e3Sopenharmony_ci    if (!GetThread()->GetEcmaVM()->ICEnabled()) {
2694514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
2704514f5e3Sopenharmony_ci        return result.GetTaggedValue();
2714514f5e3Sopenharmony_ci    }
2724514f5e3Sopenharmony_ci    TraceIC(receiver, key);
2734514f5e3Sopenharmony_ci    // do not cache element
2744514f5e3Sopenharmony_ci    if (!op.IsFastMode()) {
2754514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
2764514f5e3Sopenharmony_ci        return result.GetTaggedValue();
2774514f5e3Sopenharmony_ci    }
2784514f5e3Sopenharmony_ci
2794514f5e3Sopenharmony_ci    UpdateLoadHandler(op, key, receiver);
2804514f5e3Sopenharmony_ci    return result.GetTaggedValue();
2814514f5e3Sopenharmony_ci}
2824514f5e3Sopenharmony_ci
2834514f5e3Sopenharmony_ciJSTaggedValue LoadICRuntime::LoadOrdinaryGet(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
2844514f5e3Sopenharmony_ci{
2854514f5e3Sopenharmony_ci    icAccessor_.SetAsMega();
2864514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
2874514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
2884514f5e3Sopenharmony_ci    return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
2894514f5e3Sopenharmony_ci}
2904514f5e3Sopenharmony_ci
2914514f5e3Sopenharmony_ciinline JSTaggedValue LoadICRuntime::CallPrivateGetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
2924514f5e3Sopenharmony_ci{
2934514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
2944514f5e3Sopenharmony_ci    EcmaRuntimeCallInfo* info =
2954514f5e3Sopenharmony_ci        EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 0); // 0: getter has 0 argument
2964514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
2974514f5e3Sopenharmony_ci    JSTaggedValue resGetter = JSFunction::Call(info);
2984514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
2994514f5e3Sopenharmony_ci    return resGetter;
3004514f5e3Sopenharmony_ci}
3014514f5e3Sopenharmony_ci
3024514f5e3Sopenharmony_ciJSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
3034514f5e3Sopenharmony_ci{
3044514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
3054514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
3064514f5e3Sopenharmony_ci    JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
3074514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
3084514f5e3Sopenharmony_ci    if (!numericIndex.IsUndefined()) {
3094514f5e3Sopenharmony_ci        if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || !GetThread()->GetEcmaVM()->ICEnabled()) {
3104514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
3114514f5e3Sopenharmony_ci            return JSTaggedValue::GetProperty(GetThread(), receiver, propKey).GetValue().GetTaggedValue();
3124514f5e3Sopenharmony_ci        }
3134514f5e3Sopenharmony_ci        UpdateTypedArrayHandler(receiver);
3144514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
3154514f5e3Sopenharmony_ci        uint32_t index = static_cast<uint32_t>(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32());
3164514f5e3Sopenharmony_ci        JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
3174514f5e3Sopenharmony_ci        return JSTypedArray::FastGetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index, type);
3184514f5e3Sopenharmony_ci    } else {
3194514f5e3Sopenharmony_ci        ObjectOperator op(GetThread(), receiver, key);
3204514f5e3Sopenharmony_ci        auto result = JSHandle<JSTaggedValue>(GetThread(), JSObject::GetProperty(GetThread(), &op));
3214514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
3224514f5e3Sopenharmony_ci        if (op.GetValue().IsAccessor()) {
3234514f5e3Sopenharmony_ci            op = ObjectOperator(GetThread(), receiver, key);
3244514f5e3Sopenharmony_ci        }
3254514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
3264514f5e3Sopenharmony_ci        // ic-switch
3274514f5e3Sopenharmony_ci        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
3284514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
3294514f5e3Sopenharmony_ci            return result.GetTaggedValue();
3304514f5e3Sopenharmony_ci        }
3314514f5e3Sopenharmony_ci        TraceIC(receiver, key);
3324514f5e3Sopenharmony_ci        // do not cache element
3334514f5e3Sopenharmony_ci        if (!op.IsFastMode()) {
3344514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
3354514f5e3Sopenharmony_ci            return result.GetTaggedValue();
3364514f5e3Sopenharmony_ci        }
3374514f5e3Sopenharmony_ci        UpdateLoadHandler(op, key, receiver);
3384514f5e3Sopenharmony_ci        return result.GetTaggedValue();
3394514f5e3Sopenharmony_ci    }
3404514f5e3Sopenharmony_ci}
3414514f5e3Sopenharmony_ci
3424514f5e3Sopenharmony_ciJSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
3434514f5e3Sopenharmony_ci                                        JSHandle<JSTaggedValue> value, bool isOwn)
3444514f5e3Sopenharmony_ci{
3454514f5e3Sopenharmony_ci    ICKind kind = GetICKind();
3464514f5e3Sopenharmony_ci    if (IsValueIC(kind)) {
3474514f5e3Sopenharmony_ci        key = JSTaggedValue::ToPropertyKey(GetThread(), key);
3484514f5e3Sopenharmony_ci    }
3494514f5e3Sopenharmony_ci    if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
3504514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
3514514f5e3Sopenharmony_ci        bool success = JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true);
3524514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
3534514f5e3Sopenharmony_ci        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
3544514f5e3Sopenharmony_ci    }
3554514f5e3Sopenharmony_ci    if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
3564514f5e3Sopenharmony_ci        return StoreTypedArrayValueMiss(receiver, key, value);
3574514f5e3Sopenharmony_ci    }
3584514f5e3Sopenharmony_ci
3594514f5e3Sopenharmony_ci    // global variable find from global record firstly
3604514f5e3Sopenharmony_ci    if (kind == ICKind::NamedGlobalStoreIC || kind == ICKind::NamedGlobalTryStoreIC) {
3614514f5e3Sopenharmony_ci        JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
3624514f5e3Sopenharmony_ci        if (!box.IsUndefined()) {
3634514f5e3Sopenharmony_ci            ASSERT(box.IsPropertyBox());
3644514f5e3Sopenharmony_ci            SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue());
3654514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
3664514f5e3Sopenharmony_ci            if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
3674514f5e3Sopenharmony_ci                icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
3684514f5e3Sopenharmony_ci            }
3694514f5e3Sopenharmony_ci            return JSTaggedValue::Undefined();
3704514f5e3Sopenharmony_ci        }
3714514f5e3Sopenharmony_ci    }
3724514f5e3Sopenharmony_ci    UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
3734514f5e3Sopenharmony_ci
3744514f5e3Sopenharmony_ci    // fixme(hzzhouzebin) Open IC for SharedArray later.
3754514f5e3Sopenharmony_ci    if (receiver->IsJSSharedArray()) {
3764514f5e3Sopenharmony_ci        bool success = JSSharedArray::SetProperty(thread_, receiver, key, value, true, SCheckMode::CHECK);
3774514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
3784514f5e3Sopenharmony_ci        if (success) {
3794514f5e3Sopenharmony_ci            return JSTaggedValue::Undefined();
3804514f5e3Sopenharmony_ci        }
3814514f5e3Sopenharmony_ci        return JSTaggedValue::Exception();
3824514f5e3Sopenharmony_ci    }
3834514f5e3Sopenharmony_ci    if (key->IsJSFunction()) { // key is a private setter
3844514f5e3Sopenharmony_ci        return CallPrivateSetter(receiver, key, value);
3854514f5e3Sopenharmony_ci    }
3864514f5e3Sopenharmony_ci
3874514f5e3Sopenharmony_ci    if (key->IsSymbol() && JSSymbol::Cast(key->GetTaggedObject())->IsPrivate()) {
3884514f5e3Sopenharmony_ci        PropertyDescriptor desc(thread_);
3894514f5e3Sopenharmony_ci        if (!JSTaggedValue::IsPropertyKey(key) ||
3904514f5e3Sopenharmony_ci            !JSTaggedValue::GetOwnProperty(thread_, receiver, key, desc)) {
3914514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(thread_, "invalid or cannot find private key", JSTaggedValue::Exception());
3924514f5e3Sopenharmony_ci        }
3934514f5e3Sopenharmony_ci    }
3944514f5e3Sopenharmony_ci
3954514f5e3Sopenharmony_ci    ObjectOperator op(GetThread(), receiver, key, isOwn ? OperatorType::OWN : OperatorType::PROTOTYPE_CHAIN);
3964514f5e3Sopenharmony_ci    if (!op.IsFound()) {
3974514f5e3Sopenharmony_ci        if (kind == ICKind::NamedGlobalStoreIC) {
3984514f5e3Sopenharmony_ci            PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
3994514f5e3Sopenharmony_ci            op.SetAttr(attr);
4004514f5e3Sopenharmony_ci        } else if (kind == ICKind::NamedGlobalTryStoreIC) {
4014514f5e3Sopenharmony_ci            return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
4024514f5e3Sopenharmony_ci        }
4034514f5e3Sopenharmony_ci    }
4044514f5e3Sopenharmony_ci    bool success = false;
4054514f5e3Sopenharmony_ci    if (isOwn) {
4064514f5e3Sopenharmony_ci        bool enumerable = !(receiver->IsClassPrototype() || receiver->IsClassConstructor());
4074514f5e3Sopenharmony_ci        PropertyDescriptor desc(thread_, value, true, enumerable, true);
4084514f5e3Sopenharmony_ci        success = JSObject::DefineOwnProperty(thread_, &op, desc);
4094514f5e3Sopenharmony_ci    } else {
4104514f5e3Sopenharmony_ci        success = JSObject::SetProperty(&op, value, true);
4114514f5e3Sopenharmony_ci    }
4124514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
4134514f5e3Sopenharmony_ci    // ic-switch
4144514f5e3Sopenharmony_ci    if (!GetThread()->GetEcmaVM()->ICEnabled()) {
4154514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
4164514f5e3Sopenharmony_ci        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
4174514f5e3Sopenharmony_ci    }
4184514f5e3Sopenharmony_ci    TraceIC(receiver, key);
4194514f5e3Sopenharmony_ci    // do not cache element
4204514f5e3Sopenharmony_ci    if (!op.IsFastMode()) {
4214514f5e3Sopenharmony_ci        icAccessor_.SetAsMega();
4224514f5e3Sopenharmony_ci        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
4234514f5e3Sopenharmony_ci    }
4244514f5e3Sopenharmony_ci    if (success) {
4254514f5e3Sopenharmony_ci        UpdateStoreHandler(op, key, receiver);
4264514f5e3Sopenharmony_ci        return JSTaggedValue::Undefined();
4274514f5e3Sopenharmony_ci    }
4284514f5e3Sopenharmony_ci    return JSTaggedValue::Exception();
4294514f5e3Sopenharmony_ci}
4304514f5e3Sopenharmony_ci
4314514f5e3Sopenharmony_ciinline JSTaggedValue StoreICRuntime::CallPrivateSetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
4324514f5e3Sopenharmony_ci                                                       JSHandle<JSTaggedValue> value)
4334514f5e3Sopenharmony_ci{
4344514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
4354514f5e3Sopenharmony_ci    EcmaRuntimeCallInfo* info =
4364514f5e3Sopenharmony_ci        EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 1); // 1: setter has 1 argument
4374514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
4384514f5e3Sopenharmony_ci    info->SetCallArg(value.GetTaggedValue());
4394514f5e3Sopenharmony_ci    JSTaggedValue resSetter = JSFunction::Call(info);
4404514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
4414514f5e3Sopenharmony_ci    return resSetter;
4424514f5e3Sopenharmony_ci}
4434514f5e3Sopenharmony_ci
4444514f5e3Sopenharmony_ciJSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
4454514f5e3Sopenharmony_ci                                                       JSHandle<JSTaggedValue> value)
4464514f5e3Sopenharmony_ci{
4474514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
4484514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
4494514f5e3Sopenharmony_ci    JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
4504514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
4514514f5e3Sopenharmony_ci    if (!numericIndex.IsUndefined()) {
4524514f5e3Sopenharmony_ci        if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || value->IsECMAObject() ||
4534514f5e3Sopenharmony_ci            !GetThread()->GetEcmaVM()->ICEnabled()) {
4544514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
4554514f5e3Sopenharmony_ci            bool success = JSTaggedValue::SetProperty(GetThread(), receiver, propKey, value, true);
4564514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
4574514f5e3Sopenharmony_ci            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
4584514f5e3Sopenharmony_ci        }
4594514f5e3Sopenharmony_ci        UpdateTypedArrayHandler(receiver);
4604514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
4614514f5e3Sopenharmony_ci        uint32_t index = static_cast<uint32_t>(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32());
4624514f5e3Sopenharmony_ci        JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
4634514f5e3Sopenharmony_ci        return JSTypedArray::FastSetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index,
4644514f5e3Sopenharmony_ci                                                    value.GetTaggedValue(), type);
4654514f5e3Sopenharmony_ci    } else {
4664514f5e3Sopenharmony_ci        UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
4674514f5e3Sopenharmony_ci        ObjectOperator op(GetThread(), receiver, key);
4684514f5e3Sopenharmony_ci        bool success = JSObject::SetProperty(&op, value, true);
4694514f5e3Sopenharmony_ci        if (op.GetValue().IsAccessor()) {
4704514f5e3Sopenharmony_ci            op = ObjectOperator(GetThread(), receiver, key);
4714514f5e3Sopenharmony_ci        }
4724514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
4734514f5e3Sopenharmony_ci        // ic-switch
4744514f5e3Sopenharmony_ci        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
4754514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
4764514f5e3Sopenharmony_ci            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
4774514f5e3Sopenharmony_ci        }
4784514f5e3Sopenharmony_ci        TraceIC(receiver, key);
4794514f5e3Sopenharmony_ci        // do not cache element
4804514f5e3Sopenharmony_ci        if (!op.IsFastMode()) {
4814514f5e3Sopenharmony_ci            icAccessor_.SetAsMega();
4824514f5e3Sopenharmony_ci            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
4834514f5e3Sopenharmony_ci        }
4844514f5e3Sopenharmony_ci        if (success) {
4854514f5e3Sopenharmony_ci            UpdateStoreHandler(op, key, receiver);
4864514f5e3Sopenharmony_ci            return JSTaggedValue::Undefined();
4874514f5e3Sopenharmony_ci        }
4884514f5e3Sopenharmony_ci        return JSTaggedValue::Exception();
4894514f5e3Sopenharmony_ci    }
4904514f5e3Sopenharmony_ci}
4914514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
492