• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 #ifndef ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
17 #define ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
18 
19 #include "ecmascript/base/config.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/global_dictionary-inl.h"
22 #include "ecmascript/ic/ic_runtime_stub.h"
23 #include "ecmascript/ic/ic_handler.h"
24 #include "ecmascript/ic/ic_runtime.h"
25 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
26 #include "ecmascript/ic/proto_change_details.h"
27 #include "ecmascript/js_tagged_value-inl.h"
28 #include "ecmascript/js_array.h"
29 #include "ecmascript/js_hclass-inl.h"
30 #include "ecmascript/js_function.h"
31 #include "ecmascript/js_proxy.h"
32 #include "ecmascript/js_handle.h"
33 #include "ecmascript/object_factory-inl.h"
34 #include "ecmascript/runtime_call_id.h"
35 
36 namespace panda::ecmascript {
LoadGlobalICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue globalValue,JSTaggedValue key,uint32_t slotId,bool tryLoad)37 JSTaggedValue ICRuntimeStub::LoadGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
38                                                 JSTaggedValue globalValue, JSTaggedValue key, uint32_t slotId,
39                                                 bool tryLoad)
40 {
41     INTERPRETER_TRACE(thread, LoadGlobalICByName);
42     JSTaggedValue handler = profileTypeInfo->Get(slotId);
43     if (handler.IsHeapObject()) {
44         auto result = LoadGlobal(handler);
45         if (!result.IsHole()) {
46             return result;
47         }
48     }
49     ICKind kind = tryLoad ? ICKind::NamedGlobalTryLoadIC : ICKind::NamedGlobalLoadIC;
50     return LoadMiss(thread, profileTypeInfo, globalValue, key, slotId, kind);
51 }
52 
StoreGlobalICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue globalValue,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,bool tryStore)53 JSTaggedValue ICRuntimeStub::StoreGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
54                                                  JSTaggedValue globalValue, JSTaggedValue key,
55                                                  JSTaggedValue value, uint32_t slotId, bool tryStore)
56 {
57     INTERPRETER_TRACE(thread, StoreGlobalICByName);
58     JSTaggedValue handler = profileTypeInfo->Get(slotId);
59     if (handler.IsHeapObject()) {
60         auto result = StoreGlobal(thread, value, handler);
61         if (!result.IsHole()) {
62             return result;
63         }
64     }
65     ICKind kind = tryStore ? ICKind::NamedGlobalTryStoreIC : ICKind::NamedGlobalStoreIC;
66     return StoreMiss(thread, profileTypeInfo, globalValue, key, value, slotId, kind);
67 }
68 
CheckPolyHClass(JSTaggedValue cachedValue,JSHClass * hclass)69 JSTaggedValue ICRuntimeStub::CheckPolyHClass(JSTaggedValue cachedValue, JSHClass* hclass)
70 {
71     if (!cachedValue.IsWeak()) {
72         ASSERT(cachedValue.IsTaggedArray());
73         TaggedArray *array = TaggedArray::Cast(cachedValue.GetTaggedObject());
74         uint32_t length = array->GetLength();
75         for (uint32_t i = 0; i < length; i += 2) {  // 2 means one ic, two slot
76             auto result = array->Get(i);
77             if (!result.IsUndefined() && result.GetWeakReferent() == hclass) {
78                 return array->Get(i + 1);
79             }
80         }
81     }
82     return JSTaggedValue::Hole();
83 }
84 
TryLoadICByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue firstValue,JSTaggedValue secondValue)85 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByName(JSThread *thread, JSTaggedValue receiver,
86                                                         JSTaggedValue firstValue, JSTaggedValue secondValue)
87 {
88     INTERPRETER_TRACE(thread, TryLoadICByName);
89     if (LIKELY(receiver.IsHeapObject())) {
90         auto hclass = receiver.GetTaggedObject()->GetClass();
91         if (LIKELY(firstValue.GetWeakReferentUnChecked() == hclass)) {
92             return LoadICWithHandler(thread, receiver, receiver, secondValue);
93         }
94         JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
95         if (!cachedHandler.IsHole()) {
96             return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
97         }
98     }
99     return JSTaggedValue::Hole();
100 }
101 
LoadICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)102 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
103                                                        JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
104 {
105     INTERPRETER_TRACE(thread, LoadICByName);
106     return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::NamedLoadIC);
107 }
108 
TryLoadICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue)109 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
110                                                          JSTaggedValue firstValue, JSTaggedValue secondValue)
111 {
112     INTERPRETER_TRACE(thread, TryLoadICByValue);
113     if (receiver.IsHeapObject()) {
114         auto hclass = receiver.GetTaggedObject()->GetClass();
115         if (firstValue.GetWeakReferentUnChecked() == hclass) {
116             ASSERT(HandlerBase::IsElement(secondValue.GetInt()));
117             return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
118         }
119         // Check key
120         if (firstValue == key) {
121             JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
122             if (!cachedHandler.IsHole()) {
123                 return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
124             }
125         }
126     }
127     return JSTaggedValue::Hole();
128 }
129 
LoadICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)130 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
131                                                         JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
132 {
133     INTERPRETER_TRACE(thread, LoadICByValue);
134     return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::LoadIC);
135 }
136 
TryStoreICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)137 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByValue(JSThread *thread, JSTaggedValue receiver,
138                                                           JSTaggedValue key, JSTaggedValue firstValue,
139                                                           JSTaggedValue secondValue, JSTaggedValue value)
140 {
141     INTERPRETER_TRACE(thread, TryStoreICByValue);
142     if (receiver.IsHeapObject()) {
143         auto hclass = receiver.GetTaggedObject()->GetClass();
144         if (firstValue.GetWeakReferentUnChecked() == hclass) {
145             return StoreElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key, value, secondValue);
146         }
147         // Check key
148         if (firstValue == key) {
149             JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
150             if (!cachedHandler.IsHole()) {
151                 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
152             }
153         }
154     }
155 
156     return JSTaggedValue::Hole();
157 }
158 
StoreICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)159 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
160                                                          JSTaggedValue receiver, JSTaggedValue key,
161                                                          JSTaggedValue value, uint32_t slotId)
162 {
163     INTERPRETER_TRACE(thread, StoreICByValue);
164     return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC);
165 }
166 
TryStoreICByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)167 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByName(JSThread *thread, JSTaggedValue receiver,
168                                                          JSTaggedValue firstValue, JSTaggedValue secondValue,
169                                                          JSTaggedValue value)
170 {
171     INTERPRETER_TRACE(thread, TryStoreICByName);
172     if (receiver.IsHeapObject()) {
173         auto hclass = receiver.GetTaggedObject()->GetClass();
174         if (firstValue.GetWeakReferentUnChecked() == hclass) {
175             return StoreICWithHandler(thread, receiver, receiver, value, secondValue);
176         }
177         JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
178         if (!cachedHandler.IsHole()) {
179             return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
180         }
181     }
182     return JSTaggedValue::Hole();
183 }
184 
StoreICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)185 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
186                                                         JSTaggedValue receiver, JSTaggedValue key,
187                                                         JSTaggedValue value, uint32_t slotId)
188 {
189     INTERPRETER_TRACE(thread, StoreICByName);
190     return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::NamedStoreIC);
191 }
192 
StoreICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue value,JSTaggedValue handler)193 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JSTaggedValue receiver,
194                                                            JSTaggedValue holder,
195                                                            JSTaggedValue value, JSTaggedValue handler)
196 {
197     INTERPRETER_TRACE(thread, StoreICWithHandler);
198     if (handler.IsInt()) {
199         auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
200         if (HandlerBase::IsField(handlerInfo)) {
201             StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
202             return JSTaggedValue::Undefined();
203         }
204         ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
205         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
206         return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
207     }
208     if (handler.IsTransitionHandler()) {
209         StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
210         return JSTaggedValue::Undefined();
211     }
212     if (handler.IsTransWithProtoHandler()) {
213         return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
214     }
215     if (handler.IsPrototypeHandler()) {
216         return StorePrototype(thread, receiver, value, handler);
217     }
218     if (handler.IsPropertyBox()) {
219         return StoreGlobal(thread, value, handler);
220     }
221     if (handler.IsStoreTSHandler()) {
222         return StoreWithTS(thread, receiver, value, handler);
223     }
224     return JSTaggedValue::Undefined();
225 }
226 
StorePrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)227 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
228                                             JSTaggedValue value, JSTaggedValue handler)
229 {
230     INTERPRETER_TRACE(thread, StorePrototype);
231     ASSERT(handler.IsPrototypeHandler());
232     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
233     auto cellValue = prototypeHandler->GetProtoCell();
234     if (cellValue.IsNull()) {
235         return JSTaggedValue::Hole();
236     }
237     ASSERT(cellValue.IsProtoChangeMarker());
238     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
239     if (cell->GetHasChanged()) {
240         return JSTaggedValue::Hole();
241     }
242     auto holder = prototypeHandler->GetHolder();
243     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
244     return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
245 }
246 
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)247 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
248                                          JSTaggedValue value, JSTaggedValue handler)
249 {
250     INTERPRETER_TRACE(thread, StoreWithAOT);
251     ASSERT(handler.IsStoreTSHandler());
252     StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
253     auto cellValue = storeTSHandler->GetProtoCell();
254     ASSERT(cellValue.IsProtoChangeMarker());
255     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
256     if (cell->GetHasChanged()) {
257         return JSTaggedValue::Hole();
258     }
259     auto holder = storeTSHandler->GetHolder();
260     JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
261     auto handlerInfoInt = static_cast<uint32_t>(handlerInfo.GetInt());
262     if (HandlerBase::IsField(handlerInfoInt)) {
263         StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
264         return JSTaggedValue::Undefined();
265     }
266     ASSERT(HandlerBase::IsAccessor(handlerInfoInt) || HandlerBase::IsInternalAccessor(handlerInfoInt));
267     auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
268     return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
269 }
270 
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)271 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
272                                         JSTaggedValue handler, bool withPrototype)
273 {
274     INTERPRETER_TRACE(thread, StoreWithTransition);
275 
276     JSHClass *newHClass = nullptr;
277     uint32_t handlerInfo = 0;
278 
279     if (withPrototype) {
280         TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
281         newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
282         handlerInfo = static_cast<uint32_t>(transWithProtoHandler->GetHandlerInfo().GetInt());
283     } else {
284         TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
285         newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
286         handlerInfo = static_cast<uint32_t>(transitionHandler->GetHandlerInfo().GetInt());
287     }
288 
289     receiver->SynchronizedSetClass(newHClass);
290     ASSERT(HandlerBase::IsField(handlerInfo));
291 
292     if (!HandlerBase::IsInlinedProps(handlerInfo)) {
293         TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
294         int capacity = static_cast<int>(array->GetLength());
295         int index = HandlerBase::GetOffset(handlerInfo);
296         if (index >= capacity) {
297             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
298             [[maybe_unused]] EcmaHandleScope handleScope(thread);
299             JSHandle<TaggedArray> properties;
300             JSHandle<JSObject> objHandle(thread, receiver);
301             JSHandle<JSTaggedValue> valueHandle(thread, value);
302             if (capacity == 0) {
303                 capacity = JSObject::MIN_PROPERTIES_LENGTH;
304                 properties = factory->NewTaggedArray(capacity);
305             } else {
306                 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
307                 properties = factory->CopyArray(arrayHandle, capacity,
308                                                 JSObject::ComputePropertyCapacity(capacity));
309             }
310             properties->Set(thread, index, valueHandle);
311             objHandle->SetProperties(thread, properties);
312             return;
313         }
314         array->Set(thread, index, value);
315         return;
316     }
317     StoreField(thread, receiver, value, handlerInfo);
318 }
319 
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)320 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
321                                                  JSTaggedValue handler)
322 {
323     INTERPRETER_TRACE(thread, StoreTransWithProto);
324     ASSERT(handler.IsTransWithProtoHandler());
325     TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
326     auto cellValue = transWithProtoHandler->GetProtoCell();
327     ASSERT(cellValue.IsProtoChangeMarker());
328     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
329     if (cell->GetHasChanged()) {
330         return JSTaggedValue::Hole();
331     }
332 
333     StoreWithTransition(thread, receiver, value, handler, true);
334     return JSTaggedValue::Undefined();
335 }
336 
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint32_t handler)337 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint32_t handler)
338 {
339     INTERPRETER_TRACE(thread, StoreField);
340     int index = HandlerBase::GetOffset(handler);
341     if (HandlerBase::IsInlinedProps(handler)) {
342         SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
343         return;
344     }
345     TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
346     ASSERT(index < static_cast<int>(array->GetLength()));
347     array->Set(thread, index, value);
348 }
349 
LoadFromField(JSObject * receiver,uint32_t handlerInfo)350 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint32_t handlerInfo)
351 {
352     int index = HandlerBase::GetOffset(handlerInfo);
353     if (HandlerBase::IsInlinedProps(handlerInfo)) {
354         return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
355     }
356     return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
357 }
358 
LoadGlobal(JSTaggedValue handler)359 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
360 {
361     ASSERT(handler.IsPropertyBox());
362     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
363     if (cell->IsInvalid()) {
364         return JSTaggedValue::Hole();
365     }
366     JSTaggedValue ret = cell->GetValue();
367     ASSERT(!ret.IsAccessorData());
368     return ret;
369 }
370 
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)371 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
372 {
373     INTERPRETER_TRACE(thread, StoreGlobal);
374     ASSERT(handler.IsPropertyBox());
375     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
376     if (cell->IsInvalid()) {
377         return JSTaggedValue::Hole();
378     }
379     ASSERT(!cell->GetValue().IsAccessorData());
380     cell->SetValue(thread, value);
381     return JSTaggedValue::Undefined();
382 }
383 
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)384 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
385 {
386     INTERPRETER_TRACE(thread, LoadPrototype);
387     ASSERT(handler.IsPrototypeHandler());
388     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
389     auto cellValue = prototypeHandler->GetProtoCell();
390     ASSERT(cellValue.IsProtoChangeMarker());
391     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
392     if (cell->GetHasChanged()) {
393         return JSTaggedValue::Hole();
394     }
395     auto holder = prototypeHandler->GetHolder();
396     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
397     return LoadICWithHandler(thread, receiver, holder, handlerInfo);
398 }
399 
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)400 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
401                                                           JSTaggedValue holder, JSTaggedValue handler)
402 {
403     INTERPRETER_TRACE(thread, LoadICWithHandler);
404     if (LIKELY(handler.IsInt())) {
405         auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
406         if (LIKELY(HandlerBase::IsField(handlerInfo))) {
407             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
408         }
409         if (HandlerBase::IsNonExist(handlerInfo)) {
410             return JSTaggedValue::Undefined();
411         }
412         ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
413         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
414         return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
415     }
416 
417     if (handler.IsPrototypeHandler()) {
418         return LoadPrototype(thread, receiver, handler);
419     }
420 
421     return LoadGlobal(handler);
422 }
423 
LoadElement(JSObject * receiver,JSTaggedValue key)424 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
425 {
426     auto index = TryToElementsIndex(key);
427     if (index < 0) {
428         return JSTaggedValue::Hole();
429     }
430     uint32_t elementIndex = static_cast<uint32_t>(index);
431     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
432     if (elements->GetLength() <= elementIndex) {
433         return JSTaggedValue::Hole();
434     }
435 
436     JSTaggedValue value = elements->Get(elementIndex);
437     // TaggedArray elements
438     return value;
439 }
440 
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)441 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
442                                           JSTaggedValue value, JSTaggedValue handler)
443 {
444     INTERPRETER_TRACE(thread, StoreElement);
445     auto index = TryToElementsIndex(key);
446     if (index < 0) {
447         return JSTaggedValue::Hole();
448     }
449     uint32_t elementIndex = static_cast<uint32_t>(index);
450     if (handler.IsInt()) {
451         auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
452         [[maybe_unused]] EcmaHandleScope handleScope(thread);
453         JSHandle<JSObject> receiverHandle(thread, receiver);
454         if (HandlerBase::IsJSArray(handlerInfo)) {
455             JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
456             if (receiveValue.IsJSCOWArray()) {
457                 // Copy on write array.
458                 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
459             }
460             JSArray *arr = JSArray::Cast(*receiverHandle);
461             uint32_t oldLength = arr->GetArrayLength();
462             if (elementIndex >= oldLength) {
463                 arr->SetArrayLength(thread, elementIndex + 1);
464             }
465         }
466         TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
467         uint32_t capacity = elements->GetLength();
468         if (elementIndex >= capacity) {
469             if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
470                 return JSTaggedValue::Hole();
471             }
472             JSHandle<JSTaggedValue> valueHandle(thread, value);
473             elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
474             receiverHandle->SetElements(thread, JSTaggedValue(elements));
475             elements->Set(thread, elementIndex, valueHandle);
476             return JSTaggedValue::Undefined();
477         }
478         elements->Set(thread, elementIndex, value);
479     } else {
480         ASSERT(handler.IsPrototypeHandler());
481         PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
482         auto cellValue = prototypeHandler->GetProtoCell();
483         ASSERT(cellValue.IsProtoChangeMarker());
484         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
485         if (cell->GetHasChanged()) {
486             return JSTaggedValue::Hole();
487         }
488         JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
489         return StoreElement(thread, receiver, key, value, handlerInfo);
490     }
491     return JSTaggedValue::Undefined();
492 }
493 
TryToElementsIndex(JSTaggedValue key)494 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
495 {
496     if (LIKELY(key.IsInt())) {
497         return key.GetInt();
498     }
499 
500     if (key.IsString()) {
501         uint32_t index = 0;
502         if (JSTaggedValue::StringToElementIndex(key, &index)) {
503             return static_cast<int64_t>(index);
504         }
505     }
506 
507     if (key.IsDouble()) {
508         double number = key.GetDouble();
509         auto integer = static_cast<int32_t>(number);
510         if (number == integer) {
511             return integer;
512         }
513     }
514 
515     return -1;
516 }
517 
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)518 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
519                                       JSTaggedValue key, uint32_t slotId, ICKind kind)
520 {
521     [[maybe_unused]] EcmaHandleScope handleScope(thread);
522     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
523     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
524     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
525     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
526     return icRuntime.LoadMiss(receiverHandle, keyHandle);
527 }
528 
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind)529 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
530                                        JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind)
531 {
532     [[maybe_unused]] EcmaHandleScope handleScope(thread);
533     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
534     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
535     auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
536     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
537     StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
538     return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle);
539 }
540 }  // namespace panda::ecmascript
541 
542 #endif  // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
543