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