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