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 
23 namespace panda::ecmascript {
24 #define TRACE_IC 0  // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25 
UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> receiver)26 void 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 
UpdateLoadStringHandler(JSHandle<JSTaggedValue> receiver)91 void 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 
UpdateTypedArrayHandler(JSHandle<JSTaggedValue> receiver)101 void 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 
UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> receiver)112 void 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 
TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver, [[maybe_unused]] JSHandle<JSTaggedValue> key) const155 void 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 
LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)174 JSTaggedValue 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 
LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)225 JSTaggedValue 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 
LoadOrdinaryGet(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)283 JSTaggedValue 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 
CallPrivateGetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)291 inline 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 
LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)302 JSTaggedValue 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 
StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> value, bool isOwn)342 JSTaggedValue 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 
CallPrivateSetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> value)431 inline 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 
StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> value)444 JSTaggedValue 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