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