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