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