1/*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/ic/ic_runtime.h"
17#include "ecmascript/ic/ic_handler.h"
18#include "ecmascript/interpreter/interpreter.h"
19#include "ecmascript/interpreter/slow_runtime_stub.h"
20#include "ecmascript/js_primitive_ref.h"
21#include "ecmascript/shared_objects/js_shared_array.h"
22
23namespace panda::ecmascript {
24#define TRACE_IC 0  // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25
26void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
27                                  JSHandle<JSTaggedValue> receiver)
28{
29    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
30        return;
31    }
32    if (IsNamedIC(GetICKind())) {
33        key = JSHandle<JSTaggedValue>();
34    }
35    JSHandle<JSTaggedValue> handlerValue;
36    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
37    JSHandle<JSHClass> originhclass;
38    if (receiver->IsNumber()) {
39        receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, receiver));
40    } else if (receiver->IsString()) {
41        originhclass = JSHandle<JSHClass>(thread_, receiver->GetTaggedObject()->GetClass());
42        receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, receiver));
43    }
44    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
45    // When a transition occurs without the shadow property, AOT does not trigger the
46    // notifyprototypechange behavior, so for the case where the property does not
47    // exist and the Hclass is AOT, IC needs to be abandoned.
48    if (hclass->IsTS() && !op.IsFound()) {
49        return;
50    }
51    if (op.IsElement()) {
52        if (!op.IsFound() && hclass->IsDictionaryElement()) {
53            return;
54        }
55        handlerValue = LoadHandler::LoadElement(thread_, op);
56    } else {
57        if (!op.IsFound()) {
58            JSTaggedValue proto = hclass->GetPrototype();
59            if (!proto.IsECMAObject()) {
60                handlerValue = LoadHandler::LoadProperty(thread_, op);
61            } else {
62                handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
63            }
64        } else if (!op.IsOnPrototype()) {
65            handlerValue = LoadHandler::LoadProperty(thread_, op);
66        } else {
67            // do not support global prototype ic
68            if (IsGlobalLoadIC(GetICKind())) {
69                return;
70            }
71            handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
72        }
73    }
74
75    if (!originhclass.GetTaggedValue().IsUndefined()) {
76        hclass = originhclass;
77    }
78    if (key.IsEmpty()) {
79        icAccessor_.AddHandlerWithoutKey(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
80    } else if (op.IsElement()) {
81        // do not support global element ic
82        if (IsGlobalLoadIC(GetICKind())) {
83            return;
84        }
85        icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
86    } else {
87        icAccessor_.AddHandlerWithKey(key, JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
88    }
89}
90
91void ICRuntime::UpdateLoadStringHandler(JSHandle<JSTaggedValue> receiver)
92{
93    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
94        return;
95    }
96    JSHandle<JSTaggedValue> handlerValue = LoadHandler::LoadStringElement(thread_);
97    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
98    icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
99}
100
101void ICRuntime::UpdateTypedArrayHandler(JSHandle<JSTaggedValue> receiver)
102{
103    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
104        return;
105    }
106    JSHandle<JSTaggedValue> handlerValue =
107        LoadHandler::LoadTypedArrayElement(thread_, JSHandle<JSTypedArray>(receiver));
108    JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
109    icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
110}
111
112void ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
113                                   JSHandle<JSTaggedValue> receiver)
114{
115    if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
116        return;
117    }
118    if (IsNamedIC(GetICKind())) {
119        key = JSHandle<JSTaggedValue>();
120    }
121    JSHandle<JSTaggedValue> handlerValue;
122    ASSERT(op.IsFound());
123
124    if (op.IsTransition()) {
125        if (op.IsOnPrototype()) {
126            JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
127            handlerValue = TransWithProtoHandler::StoreTransition(thread_, op, hclass);
128        } else {
129            handlerValue = TransitionHandler::StoreTransition(thread_, op);
130        }
131    } else if (op.IsOnPrototype()) {
132        // do not support global prototype ic
133        if (IsGlobalStoreIC(GetICKind())) {
134            return;
135        }
136        JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
137        handlerValue = PrototypeHandler::StorePrototype(thread_, op, hclass);
138    } else {
139        handlerValue = StoreHandler::StoreProperty(thread_, op);
140    }
141
142    if (key.IsEmpty()) {
143        icAccessor_.AddHandlerWithoutKey(receiverHClass_, handlerValue);
144    } else if (op.IsElement()) {
145        // do not support global element ic
146        if (IsGlobalStoreIC(GetICKind())) {
147            return;
148        }
149        icAccessor_.AddElementHandler(receiverHClass_, handlerValue);
150    } else {
151        icAccessor_.AddHandlerWithKey(key, receiverHClass_, handlerValue);
152    }
153}
154
155void ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
156                        [[maybe_unused]] JSHandle<JSTaggedValue> key) const
157{
158#if TRACE_IC
159    auto kind = ICKindToString(GetICKind());
160    auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
161    if (key->IsString()) {
162        auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
163        LOG_ECMA(ERROR) << kind << " miss key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
164                            << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
165                            << ", state is " << state;
166    } else {
167        LOG_ECMA(ERROR) << kind << " miss " << ", state is "
168                            << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
169                            << state;
170    }
171#endif
172}
173
174JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
175{
176    JSTaggedValue::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
177    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
178
179    if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) && !receiver->IsString()) {
180        icAccessor_.SetAsMega();
181        JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
182        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
183        return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
184    }
185    if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
186        return LoadTypedArrayValueMiss(receiver, key);
187    }
188    // fixme(hzzhouzebin) Open IC for SharedArray later.
189    if (receiver->IsJSSharedArray()) {
190        return JSSharedArray::GetProperty(thread_, receiver, key, SCheckMode::CHECK).GetValue().GetTaggedValue();
191    }
192    ObjectOperator op(GetThread(), receiver, key);
193    auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
194    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
195
196    if (receiver->IsString()) {
197         // do not cache element
198        if (!op.IsFastMode()) {
199            icAccessor_.SetAsMega();
200            return result.GetTaggedValue();
201        }
202        UpdateLoadStringHandler(receiver);
203    } else {
204        if (op.GetValue().IsAccessor()) {
205            op = ObjectOperator(GetThread(), receiver, key);
206        }
207        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
208        // ic-switch
209        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
210            icAccessor_.SetAsMega();
211            return result.GetTaggedValue();
212        }
213        TraceIC(receiver, key);
214        // do not cache element
215        if (!op.IsFastMode()) {
216            icAccessor_.SetAsMega();
217            return result.GetTaggedValue();
218        }
219        UpdateLoadHandler(op, key, receiver);
220    }
221
222    return result.GetTaggedValue();
223}
224
225JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
226{
227    if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) &&
228         !receiver->IsString() && !receiver->IsNumber()) {
229        return LoadOrdinaryGet(receiver, key);
230    }
231
232    ICKind kind = GetICKind();
233    // global variable find from global record firstly
234    if (kind == ICKind::NamedGlobalLoadIC || kind == ICKind::NamedGlobalTryLoadIC) {
235        JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
236        if (!box.IsUndefined()) {
237            ASSERT(box.IsPropertyBox());
238            if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
239                icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
240            }
241            return PropertyBox::Cast(box.GetTaggedObject())->GetValue();
242        }
243    }
244
245    if (key->IsJSFunction()) { // key is a private getter
246        return CallPrivateGetter(receiver, key);
247    }
248
249    if (key->IsSymbol() && JSSymbol::Cast(key->GetTaggedObject())->IsPrivate()) {
250        PropertyDescriptor desc(thread_);
251        if (!JSTaggedValue::IsPropertyKey(key) ||
252            !JSTaggedValue::GetOwnProperty(thread_, receiver, key, desc)) {
253            THROW_TYPE_ERROR_AND_RETURN(thread_, "invalid or cannot find private key", JSTaggedValue::Exception());
254        }
255    }
256
257    ObjectOperator op(GetThread(), receiver, key);
258    auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
259    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
260    if (op.GetValue().IsAccessor()) {
261        op = ObjectOperator(GetThread(), receiver, key);
262    }
263    if (!op.IsFound() && kind == ICKind::NamedGlobalTryLoadIC) {
264        return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
265    }
266    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
267    // ic-switch
268    if (!GetThread()->GetEcmaVM()->ICEnabled()) {
269        icAccessor_.SetAsMega();
270        return result.GetTaggedValue();
271    }
272    TraceIC(receiver, key);
273    // do not cache element
274    if (!op.IsFastMode()) {
275        icAccessor_.SetAsMega();
276        return result.GetTaggedValue();
277    }
278
279    UpdateLoadHandler(op, key, receiver);
280    return result.GetTaggedValue();
281}
282
283JSTaggedValue LoadICRuntime::LoadOrdinaryGet(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
284{
285    icAccessor_.SetAsMega();
286    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
287    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
288    return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
289}
290
291inline JSTaggedValue LoadICRuntime::CallPrivateGetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
292{
293    JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
294    EcmaRuntimeCallInfo* info =
295        EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 0); // 0: getter has 0 argument
296    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
297    JSTaggedValue resGetter = JSFunction::Call(info);
298    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
299    return resGetter;
300}
301
302JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
303{
304    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
305    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
306    JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
307    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
308    if (!numericIndex.IsUndefined()) {
309        if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || !GetThread()->GetEcmaVM()->ICEnabled()) {
310            icAccessor_.SetAsMega();
311            return JSTaggedValue::GetProperty(GetThread(), receiver, propKey).GetValue().GetTaggedValue();
312        }
313        UpdateTypedArrayHandler(receiver);
314        JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
315        uint32_t index = static_cast<uint32_t>(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32());
316        JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
317        return JSTypedArray::FastGetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index, type);
318    } else {
319        ObjectOperator op(GetThread(), receiver, key);
320        auto result = JSHandle<JSTaggedValue>(GetThread(), JSObject::GetProperty(GetThread(), &op));
321        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
322        if (op.GetValue().IsAccessor()) {
323            op = ObjectOperator(GetThread(), receiver, key);
324        }
325        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
326        // ic-switch
327        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
328            icAccessor_.SetAsMega();
329            return result.GetTaggedValue();
330        }
331        TraceIC(receiver, key);
332        // do not cache element
333        if (!op.IsFastMode()) {
334            icAccessor_.SetAsMega();
335            return result.GetTaggedValue();
336        }
337        UpdateLoadHandler(op, key, receiver);
338        return result.GetTaggedValue();
339    }
340}
341
342JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
343                                        JSHandle<JSTaggedValue> value, bool isOwn)
344{
345    ICKind kind = GetICKind();
346    if (IsValueIC(kind)) {
347        key = JSTaggedValue::ToPropertyKey(GetThread(), key);
348    }
349    if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
350        icAccessor_.SetAsMega();
351        bool success = JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true);
352        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
353        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
354    }
355    if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
356        return StoreTypedArrayValueMiss(receiver, key, value);
357    }
358
359    // global variable find from global record firstly
360    if (kind == ICKind::NamedGlobalStoreIC || kind == ICKind::NamedGlobalTryStoreIC) {
361        JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
362        if (!box.IsUndefined()) {
363            ASSERT(box.IsPropertyBox());
364            SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue());
365            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
366            if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
367                icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
368            }
369            return JSTaggedValue::Undefined();
370        }
371    }
372    UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
373
374    // fixme(hzzhouzebin) Open IC for SharedArray later.
375    if (receiver->IsJSSharedArray()) {
376        bool success = JSSharedArray::SetProperty(thread_, receiver, key, value, true, SCheckMode::CHECK);
377        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
378        if (success) {
379            return JSTaggedValue::Undefined();
380        }
381        return JSTaggedValue::Exception();
382    }
383    if (key->IsJSFunction()) { // key is a private setter
384        return CallPrivateSetter(receiver, key, value);
385    }
386
387    if (key->IsSymbol() && JSSymbol::Cast(key->GetTaggedObject())->IsPrivate()) {
388        PropertyDescriptor desc(thread_);
389        if (!JSTaggedValue::IsPropertyKey(key) ||
390            !JSTaggedValue::GetOwnProperty(thread_, receiver, key, desc)) {
391            THROW_TYPE_ERROR_AND_RETURN(thread_, "invalid or cannot find private key", JSTaggedValue::Exception());
392        }
393    }
394
395    ObjectOperator op(GetThread(), receiver, key, isOwn ? OperatorType::OWN : OperatorType::PROTOTYPE_CHAIN);
396    if (!op.IsFound()) {
397        if (kind == ICKind::NamedGlobalStoreIC) {
398            PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
399            op.SetAttr(attr);
400        } else if (kind == ICKind::NamedGlobalTryStoreIC) {
401            return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
402        }
403    }
404    bool success = false;
405    if (isOwn) {
406        bool enumerable = !(receiver->IsClassPrototype() || receiver->IsClassConstructor());
407        PropertyDescriptor desc(thread_, value, true, enumerable, true);
408        success = JSObject::DefineOwnProperty(thread_, &op, desc);
409    } else {
410        success = JSObject::SetProperty(&op, value, true);
411    }
412    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
413    // ic-switch
414    if (!GetThread()->GetEcmaVM()->ICEnabled()) {
415        icAccessor_.SetAsMega();
416        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
417    }
418    TraceIC(receiver, key);
419    // do not cache element
420    if (!op.IsFastMode()) {
421        icAccessor_.SetAsMega();
422        return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
423    }
424    if (success) {
425        UpdateStoreHandler(op, key, receiver);
426        return JSTaggedValue::Undefined();
427    }
428    return JSTaggedValue::Exception();
429}
430
431inline JSTaggedValue StoreICRuntime::CallPrivateSetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
432                                                       JSHandle<JSTaggedValue> value)
433{
434    JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
435    EcmaRuntimeCallInfo* info =
436        EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 1); // 1: setter has 1 argument
437    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
438    info->SetCallArg(value.GetTaggedValue());
439    JSTaggedValue resSetter = JSFunction::Call(info);
440    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
441    return resSetter;
442}
443
444JSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
445                                                       JSHandle<JSTaggedValue> value)
446{
447    JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
448    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
449    JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
450    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
451    if (!numericIndex.IsUndefined()) {
452        if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || value->IsECMAObject() ||
453            !GetThread()->GetEcmaVM()->ICEnabled()) {
454            icAccessor_.SetAsMega();
455            bool success = JSTaggedValue::SetProperty(GetThread(), receiver, propKey, value, true);
456            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
457            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
458        }
459        UpdateTypedArrayHandler(receiver);
460        JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
461        uint32_t index = static_cast<uint32_t>(JSTaggedValue::ToInteger(GetThread(), indexHandle).ToInt32());
462        JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
463        return JSTypedArray::FastSetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index,
464                                                    value.GetTaggedValue(), type);
465    } else {
466        UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
467        ObjectOperator op(GetThread(), receiver, key);
468        bool success = JSObject::SetProperty(&op, value, true);
469        if (op.GetValue().IsAccessor()) {
470            op = ObjectOperator(GetThread(), receiver, key);
471        }
472        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
473        // ic-switch
474        if (!GetThread()->GetEcmaVM()->ICEnabled()) {
475            icAccessor_.SetAsMega();
476            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
477        }
478        TraceIC(receiver, key);
479        // do not cache element
480        if (!op.IsFastMode()) {
481            icAccessor_.SetAsMega();
482            return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
483        }
484        if (success) {
485            UpdateStoreHandler(op, key, receiver);
486            return JSTaggedValue::Undefined();
487        }
488        return JSTaggedValue::Exception();
489    }
490}
491}  // namespace panda::ecmascript
492