• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ic/mega_ic_cache.h"
21 #include "ecmascript/ic/profile_type_info.h"
22 #include "ecmascript/interpreter/slow_runtime_stub.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/js_hclass-inl.h"
25 #include "ecmascript/js_hclass.h"
26 #include "ecmascript/js_primitive_ref.h"
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/shared_objects/js_shared_array.h"
29 
30 namespace panda::ecmascript {
31 
GetHandler(const ObjectOperator & op,const JSHandle<JSHClass> & hclass,JSHandle<JSTaggedValue> & handlerValue)32 bool ICRuntime::GetHandler(const ObjectOperator &op, const JSHandle<JSHClass> &hclass,
33                            JSHandle<JSTaggedValue> &handlerValue)
34 {
35     // Solve Global IC.
36     if (IsGlobalLoadIC(GetICKind())) {
37         // Not support global element ic
38         if (op.IsElement()) {
39             return false;
40         }
41         // Not support global not found ic
42         if (!op.IsFound()) {
43             return false;
44         }
45         // Not support global prototype ic
46         if (op.IsOnPrototype()) {
47             return false;
48         }
49         handlerValue = LoadHandler::LoadProperty(thread_, op);
50         return true;
51     }
52 
53     // Solve Element IC.
54     if (op.IsElement()) {
55         // Not support not found element ic
56         if (!op.IsFound()) {
57             return false;
58         }
59         handlerValue = LoadHandler::LoadElement(thread_, op);
60         return true;
61     }
62 
63     // Solve Not Found IC.
64     if (!op.IsFound()) {
65         // Not support not found ic for sendable
66         if (hclass->IsJSShared()) {
67             return false;
68         }
69         // Not support not found ic for global object
70         if (hclass->IsJSGlobalObject()) {
71             return false;
72         }
73         JSTaggedValue proto = hclass->GetPrototype();
74         // If proto is not an EcmaObject,
75         // it means that there is no need to search for the prototype chain.
76         if (!proto.IsECMAObject()) {
77             handlerValue = LoadHandler::LoadProperty(thread_, op);
78         } else {
79             handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
80         }
81         return true;
82     }
83 
84     // Solve IC On itself.
85     if (!op.IsOnPrototype()) {
86         handlerValue = LoadHandler::LoadProperty(thread_, op);
87         return true;
88     }
89 
90     // Solve IC On Prototype.
91     // Not support prototype ic for sendable
92     if (hclass->IsJSShared()) {
93         return false;
94     }
95     handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
96     return true;
97 }
98 
UpdateLoadHandler(const ObjectOperator & op,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> receiver)99 void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
100                                   JSHandle<JSTaggedValue> receiver)
101 {
102     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
103         return;
104     }
105     ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
106     JSHandle<JSTaggedValue> handlerValue;
107     JSHandle<JSHClass> originhclass;
108     if (receiver->IsNumber()) {
109         receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, receiver));
110     } else if (receiver->IsString()) {
111         originhclass = JSHandle<JSHClass>(thread_, receiver->GetTaggedObject()->GetClass());
112         receiver = JSHandle<JSTaggedValue>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, receiver));
113     }
114     JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
115 
116     if (!GetHandler(op, hclass, handlerValue)) {
117         return;
118     }
119 
120     if (!originhclass.GetTaggedValue().IsUndefined()) {
121         hclass = originhclass;
122     }
123     if (IsMegaIC() && receiver->IsHeapObject()) {
124         MegaICCache *cache = thread_->GetLoadMegaICCache();
125         ASSERT(cache != nullptr);
126         cache->Set(receiver->GetTaggedObject()->GetClass(), key.GetTaggedValue(), handlerValue.GetTaggedValue(),
127                    thread_);
128         return;
129     }
130 
131     if (IsNamedIC(GetICKind())) {
132         icAccessor_.AddHandlerWithoutKey(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue, key, MegaICCache::Load);
133     } else if (op.IsElement()) {
134         icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
135     } else {
136         icAccessor_.AddHandlerWithKey(key, JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
137     }
138 }
139 
UpdateLoadStringHandler(JSHandle<JSTaggedValue> receiver)140 void ICRuntime::UpdateLoadStringHandler(JSHandle<JSTaggedValue> receiver)
141 {
142     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
143         return;
144     }
145     JSHandle<JSTaggedValue> handlerValue = LoadHandler::LoadStringElement(thread_);
146     JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
147     icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
148 }
149 
UpdateTypedArrayHandler(JSHandle<JSTaggedValue> receiver)150 void ICRuntime::UpdateTypedArrayHandler(JSHandle<JSTaggedValue> receiver)
151 {
152     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
153         return;
154     }
155     JSHandle<JSTaggedValue> handlerValue =
156         LoadHandler::LoadTypedArrayElement(thread_, JSHandle<JSTypedArray>(receiver));
157     JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
158     icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
159 }
160 
UpdateStoreHandler(const ObjectOperator & op,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> receiver)161 void ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
162                                    JSHandle<JSTaggedValue> receiver)
163 {
164     JSHandle<JSTaggedValue> handlerValue;
165     ASSERT(op.IsFound());
166     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
167         return;
168     }
169 
170     if (op.IsTransition()) {
171         if (op.IsOnPrototype()) {
172             JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
173             handlerValue = TransWithProtoHandler::StoreTransition(thread_, op, hclass);
174         } else {
175             handlerValue = TransitionHandler::StoreTransition(thread_, op);
176         }
177     } else if (op.IsOnPrototype()) {
178         // do not support global prototype ic
179         if (IsGlobalStoreIC(GetICKind())) {
180             return;
181         }
182         JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
183         handlerValue = PrototypeHandler::StorePrototype(thread_, op, hclass);
184     } else {
185         handlerValue = StoreHandler::StoreProperty(thread_, op);
186     }
187 
188     if (IsMegaIC() && receiver->IsHeapObject()) {
189         MegaICCache *cache = thread_->GetStoreMegaICCache();
190         cache->Set(JSHClass::Cast(receiverHClass_->GetTaggedObject()), **key, **handlerValue, thread_);
191         return;
192     }
193 
194     if (IsNamedIC(GetICKind())) {
195         icAccessor_.AddHandlerWithoutKey(receiverHClass_, handlerValue, key, MegaICCache::Store);
196     } else if (op.IsElement()) {
197         // do not support global element ic
198         if (IsGlobalStoreIC(GetICKind())) {
199             return;
200         }
201         icAccessor_.AddElementHandler(receiverHClass_, handlerValue);
202     } else {
203         icAccessor_.AddHandlerWithKey(key, receiverHClass_, handlerValue);
204     }
205 }
206 
LoadValueMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)207 JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
208 {
209     JSTaggedValue::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
210     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
211 
212     if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) && !receiver->IsString()) {
213         icAccessor_.SetAsMega();
214         JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
215         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
216         return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
217     }
218     if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
219         return LoadTypedArrayValueMiss(receiver, key);
220     }
221     // fixme(hzzhouzebin) Open IC for SharedArray later.
222     if (receiver->IsJSSharedArray()) {
223         return JSSharedArray::GetProperty(thread_, receiver, key, SCheckMode::CHECK).GetValue().GetTaggedValue();
224     }
225     ObjectOperator op(GetThread(), receiver, key);
226     auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
227     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
228 
229     if (receiver->IsString()) {
230          // do not cache element
231         if (!op.IsFastMode()) {
232             icAccessor_.SetAsMega();
233             return result.GetTaggedValue();
234         }
235         UpdateLoadStringHandler(receiver);
236     } else {
237         if (op.GetValue().IsAccessor()) {
238             op = ObjectOperator(GetThread(), receiver, key);
239         }
240         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
241         // ic-switch
242         if (!GetThread()->GetEcmaVM()->ICEnabled()) {
243             icAccessor_.SetAsMega();
244             return result.GetTaggedValue();
245         }
246         TraceIC(GetThread(), receiver, key);
247         // do not cache element
248         if (!op.IsFastMode()) {
249             icAccessor_.SetAsMega();
250             return result.GetTaggedValue();
251         }
252         UpdateLoadHandler(op, key, receiver);
253     }
254 
255     return result.GetTaggedValue();
256 }
257 
LoadMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)258 JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
259 {
260     if ((!receiver->IsJSObject() || receiver->HasOrdinaryGet()) &&
261          !receiver->IsString() && !receiver->IsNumber()) {
262         return LoadOrdinaryGet(receiver, key);
263     }
264 
265     ICKind kind = GetICKind();
266     // global variable find from global record firstly
267     if (kind == ICKind::NamedGlobalLoadIC || kind == ICKind::NamedGlobalTryLoadIC) {
268         JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
269         if (!box.IsUndefined()) {
270             ASSERT(box.IsPropertyBox());
271             if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
272                 icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
273             }
274             return PropertyBox::Cast(box.GetTaggedObject())->GetValue();
275         }
276     }
277 
278     if (key->IsJSFunction()) { // key is a private getter
279         return CallPrivateGetter(receiver, key);
280     }
281 
282     ObjectOperator op(GetThread(), receiver, key);
283     auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
284     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
285     if (op.GetValue().IsAccessor()) {
286         op = ObjectOperator(GetThread(), receiver, key);
287     }
288     if (!op.IsFound() && kind == ICKind::NamedGlobalTryLoadIC) {
289         return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
290     }
291     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
292     // ic-switch
293     if (!GetThread()->GetEcmaVM()->ICEnabled()) {
294         icAccessor_.SetAsMega();
295         return result.GetTaggedValue();
296     }
297     TraceIC(GetThread(), receiver, key);
298 
299 #if ENABLE_NEXT_OPTIMIZATION
300     if (!op.IsFastMode() && op.IsFound()) {
301         icAccessor_.SetAsMegaForTraceSlowMode(op);
302         return result.GetTaggedValue();
303     }
304 #elif
305     if (!op.IsFastMode()) {
306         icAccessor_.SetAsMegaForTraceSlowMode(op);
307         return result.GetTaggedValue();
308     }
309 #endif
310     UpdateLoadHandler(op, key, receiver);
311     return result.GetTaggedValue();
312 }
313 
LoadOrdinaryGet(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)314 JSTaggedValue LoadICRuntime::LoadOrdinaryGet(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
315 {
316     icAccessor_.SetAsMega();
317     JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread_, key);
318     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
319     return JSTaggedValue::GetProperty(thread_, receiver, propKey).GetValue().GetTaggedValue();
320 }
321 
CallPrivateGetter(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)322 inline JSTaggedValue LoadICRuntime::CallPrivateGetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
323 {
324     JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
325     EcmaRuntimeCallInfo* info =
326         EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 0); // 0: getter has 0 argument
327     JSTaggedValue resGetter = JSFunction::Call(info);
328     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
329     return resGetter;
330 }
331 
LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)332 JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
333 {
334     JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
335     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
336     JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
337     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
338     if (!numericIndex.IsUndefined()) {
339         if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || !GetThread()->GetEcmaVM()->ICEnabled()) {
340             icAccessor_.SetAsMega();
341             return JSTaggedValue::GetProperty(GetThread(), receiver, propKey).GetValue().GetTaggedValue();
342         }
343         UpdateTypedArrayHandler(receiver);
344         JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
345         JSTaggedNumber integerValue = JSTaggedValue::ToInteger(GetThread(), indexHandle);
346         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
347         uint32_t index = static_cast<uint32_t>(integerValue.ToInt32());
348         JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
349         return JSTypedArray::FastGetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index, type);
350     } else {
351         ObjectOperator op(GetThread(), receiver, key);
352         auto result = JSHandle<JSTaggedValue>(GetThread(), JSObject::GetProperty(GetThread(), &op));
353         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
354         if (op.GetValue().IsAccessor()) {
355             op = ObjectOperator(GetThread(), receiver, key);
356         }
357         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
358         // ic-switch
359         if (!GetThread()->GetEcmaVM()->ICEnabled()) {
360             icAccessor_.SetAsMega();
361             return result.GetTaggedValue();
362         }
363         TraceIC(GetThread(), receiver, key);
364         // do not cache element
365         if (!op.IsFastMode()) {
366             icAccessor_.SetAsMega();
367             return result.GetTaggedValue();
368         }
369         UpdateLoadHandler(op, key, receiver);
370         return result.GetTaggedValue();
371     }
372 }
373 
StoreMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value,bool isOwn)374 JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
375                                         JSHandle<JSTaggedValue> value, bool isOwn)
376 {
377     ICKind kind = GetICKind();
378     if (IsValueIC(kind)) {
379         key = JSTaggedValue::ToPropertyKey(GetThread(), key);
380     }
381     if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
382         icAccessor_.SetAsMega();
383         JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true);
384         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
385         return JSTaggedValue::Undefined();
386     }
387     if (receiver->IsTypedArray() || receiver->IsSharedTypedArray()) {
388         return StoreTypedArrayValueMiss(receiver, key, value);
389     }
390 
391     // global variable find from global record firstly
392     if (kind == ICKind::NamedGlobalStoreIC || kind == ICKind::NamedGlobalTryStoreIC) {
393         JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
394         if (!box.IsUndefined()) {
395             ASSERT(box.IsPropertyBox());
396             SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue());
397             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
398             if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
399                 icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
400             }
401             return JSTaggedValue::Undefined();
402         }
403     }
404     UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
405 
406     // fixme(hzzhouzebin) Open IC for SharedArray later.
407     if (receiver->IsJSSharedArray()) {
408         bool success = JSSharedArray::SetProperty(thread_, receiver, key, value, true, SCheckMode::CHECK);
409         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
410         return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
411     }
412     if (key->IsJSFunction()) { // key is a private setter
413         return CallPrivateSetter(receiver, key, value);
414     }
415 
416     ObjectOperator op(GetThread(), receiver, key, isOwn ? OperatorType::OWN : OperatorType::PROTOTYPE_CHAIN);
417     if (!op.IsFound()) {
418         if (kind == ICKind::NamedGlobalStoreIC) {
419             PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
420             op.SetAttr(attr);
421         } else if (kind == ICKind::NamedGlobalTryStoreIC) {
422             return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
423         }
424     }
425 
426     bool success = false;
427     // If op is Accessor, it may change the properties of receiver or receiver's proto,
428     // causing IC compute errors, so move SetPropertyForAccessor to be executed after UpdateStoreHandler.
429     bool isAccessor = false;
430     if (isOwn) {
431         bool enumerable = !(receiver->IsClassPrototype() || receiver->IsClassConstructor());
432         PropertyDescriptor desc(thread_, value, true, enumerable, true);
433         success = JSObject::DefineOwnProperty(thread_, &op, desc);
434     } else {
435         success = JSObject::SetPropertyForData(&op, value, &isAccessor);
436     }
437     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
438 
439     // IC Disable
440     if (!GetThread()->GetEcmaVM()->ICEnabled() || !op.IsFastMode()) {
441         icAccessor_.SetAsMega();
442         if (!success) {
443             return JSTaggedValue::Exception();
444         }
445         if (isAccessor) {
446             return HandleAccesor(&op, value);
447         }
448         return JSTaggedValue::Undefined();
449     }
450 
451     TraceIC(GetThread(), receiver, key);
452     if (success) {
453         UpdateStoreHandler(op, key, receiver);
454     }
455     if (isAccessor) {
456         return HandleAccesor(&op, value);
457     }
458     return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
459 }
460 
CallPrivateSetter(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)461 inline JSTaggedValue StoreICRuntime::CallPrivateSetter(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
462                                                        JSHandle<JSTaggedValue> value)
463 {
464     JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
465     EcmaRuntimeCallInfo* info =
466         EcmaInterpreter::NewRuntimeCallInfo(thread_, key, receiver, undefined, 1); // 1: setter has 1 argument
467     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
468     info->SetCallArg(value.GetTaggedValue());
469     JSTaggedValue resSetter = JSFunction::Call(info);
470     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
471     return resSetter;
472 }
473 
StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)474 JSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
475                                                        JSHandle<JSTaggedValue> value)
476 {
477     JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(GetThread(), key);
478     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
479     JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(GetThread(), propKey);
480     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
481     if (!numericIndex.IsUndefined()) {
482         if (!JSTypedArray::IsValidIntegerIndex(receiver, numericIndex) || value->IsECMAObject() ||
483             !GetThread()->GetEcmaVM()->ICEnabled()) {
484             icAccessor_.SetAsMega();
485             bool success = JSTaggedValue::SetProperty(GetThread(), receiver, propKey, value, true);
486             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
487             return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
488         }
489         UpdateTypedArrayHandler(receiver);
490         JSHandle<JSTaggedValue> indexHandle(GetThread(), numericIndex);
491         JSTaggedNumber integerValue = JSTaggedValue::ToInteger(GetThread(), indexHandle);
492         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
493         uint32_t index = static_cast<uint32_t>(integerValue.ToInt32());
494         JSType type = receiver->GetTaggedObject()->GetClass()->GetObjectType();
495         return JSTypedArray::FastSetPropertyByIndex(GetThread(), receiver.GetTaggedValue(), index,
496                                                     value.GetTaggedValue(), type);
497     } else {
498         UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
499         ObjectOperator op(GetThread(), receiver, key);
500 
501         // If op is Accessor, it may change the properties of receiver or receiver's proto,
502         // causing IC compute errors, so move SetPropertyForAccessor to be executed after UpdateStoreHandler.
503         bool isAccessor = false;
504         bool success = JSObject::SetPropertyForData(&op, value, &isAccessor);
505         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
506 
507         // IC Disable
508         if (!GetThread()->GetEcmaVM()->ICEnabled() || !op.IsFastMode()) {
509             icAccessor_.SetAsMega();
510             if (!success) {
511                 return JSTaggedValue::Exception();
512             }
513             if (isAccessor) {
514                 return HandleAccesor(&op, value);
515             }
516             return JSTaggedValue::Undefined();
517         }
518 
519         TraceIC(GetThread(), receiver, key);
520         if (success) {
521             UpdateStoreHandler(op, key, receiver);
522         }
523         if (isAccessor) {
524             return HandleAccesor(&op, value);
525         }
526         return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
527     }
528 }
529 
HandleAccesor(ObjectOperator * op,const JSHandle<JSTaggedValue> & value)530 JSTaggedValue StoreICRuntime::HandleAccesor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value)
531 {
532     bool success = JSObject::SetPropertyForAccessor(op, value);
533     if (thread_->HasPendingException()) {
534         icAccessor_.SetAsMega();
535         return JSTaggedValue::Exception();
536     }
537     return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
538 }
539 
TraceIC(JSThread * thread,JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key) const540 void ICRuntime::TraceIC([[maybe_unused]] JSThread *thread,
541                         [[maybe_unused]] JSHandle<JSTaggedValue> receiver,
542                         [[maybe_unused]] JSHandle<JSTaggedValue> key) const
543 {
544 #if ECMASCRIPT_ENABLE_TRACE_IC
545     // If BackTrace affects IC, can choose not to execute it.
546     std::string strTraceIC = "Miss Func BackTrace: ";
547     std::vector<JsFrameInfo> jsStackInfo = JsStackInfo::BuildJsStackInfo(thread, true);
548     if (jsStackInfo.empty()) {
549         strTraceIC += "empty";
550     } else {
551         JsFrameInfo jsFrameInfo = jsStackInfo.front();
552         size_t pos = jsFrameInfo.pos.find(':', 0);
553         if (pos != CString::npos) {
554             int lineNumber = std::stoi(jsFrameInfo.pos.substr(0, pos));
555             int columnNumber = std::stoi(jsFrameInfo.pos.substr(pos + 1));
556             auto sourceMapcb = thread->GetEcmaVM()->GetSourceMapTranslateCallback();
557             if (sourceMapcb != nullptr && !jsFrameInfo.fileName.empty()) {
558                 sourceMapcb(jsFrameInfo.fileName, lineNumber, columnNumber, jsFrameInfo.packageName);
559             }
560         }
561         strTraceIC += "funcName: " + jsFrameInfo.functionName + ", url: " +
562             jsFrameInfo.fileName + ":" + jsFrameInfo.pos;
563     }
564     LOG_ECMA(ERROR) << strTraceIC;
565 
566     auto kind = ICKindToString(GetICKind());
567     bool primitiveIc = false;
568     if (receiver->IsNumber() || receiver->IsString()) {
569         primitiveIc = true;
570     }
571     auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
572     if (key->IsString()) {
573         auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
574         LOG_ECMA(ERROR) << kind << " miss, key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
575                         << ", icstate is: " << state
576                         << ", slotid is: " << GetSlotId();
577     } else {
578         LOG_ECMA(ERROR) << kind << " miss, "
579                         << ", icstate is " << state
580                         << ", slotid is:" << GetSlotId();
581     }
582     if (primitiveIc) {
583         LOG_ECMA(ERROR) << "primitiveIc ";
584     } else {
585         JSHClass *jshclass = receiver->GetTaggedObject()->GetClass();
586         LOG_ECMA(ERROR) << "receiver DictionaryMode is: " << jshclass->IsDictionaryMode()
587                         << ", hclass is: "<< std::hex << jshclass;
588     }
589 #endif
590 }
591 }  // namespace panda::ecmascript
592