• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 != JSTaggedValue::Undefined() && 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     ASSERT(cellValue.IsProtoChangeMarker());
235     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
236     if (cell->GetHasChanged()) {
237         return JSTaggedValue::Hole();
238     }
239     auto holder = prototypeHandler->GetHolder();
240     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
241     return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
242 }
243 
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)244 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
245                                          JSTaggedValue value, JSTaggedValue handler)
246 {
247     INTERPRETER_TRACE(thread, StoreWithAOT);
248     ASSERT(handler.IsStoreTSHandler());
249     StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
250     auto cellValue = storeTSHandler->GetProtoCell();
251     ASSERT(cellValue.IsProtoChangeMarker());
252     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
253     if (cell->GetHasChanged()) {
254         return JSTaggedValue::Hole();
255     }
256     auto holder = storeTSHandler->GetHolder();
257     JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
258     auto handlerInfoInt = static_cast<uint32_t>(handlerInfo.GetInt());
259     if (HandlerBase::IsField(handlerInfoInt)) {
260         StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
261         return JSTaggedValue::Undefined();
262     }
263     ASSERT(HandlerBase::IsAccessor(handlerInfoInt) || HandlerBase::IsInternalAccessor(handlerInfoInt));
264     auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
265     return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
266 }
267 
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)268 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
269                                         JSTaggedValue handler, bool withPrototype)
270 {
271     INTERPRETER_TRACE(thread, StoreWithTransition);
272 
273     JSHClass *newHClass = nullptr;
274     uint32_t handlerInfo = 0;
275 
276     if (withPrototype) {
277         TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
278         newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
279         handlerInfo = static_cast<uint32_t>(transWithProtoHandler->GetHandlerInfo().GetInt());
280     } else {
281         TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
282         newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
283         handlerInfo = static_cast<uint32_t>(transitionHandler->GetHandlerInfo().GetInt());
284     }
285 
286     receiver->SetClass(newHClass);
287     ASSERT(HandlerBase::IsField(handlerInfo));
288 
289     if (!HandlerBase::IsInlinedProps(handlerInfo)) {
290         TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
291         int capacity = static_cast<int>(array->GetLength());
292         int index = HandlerBase::GetOffset(handlerInfo);
293         if (index >= capacity) {
294             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
295             [[maybe_unused]] EcmaHandleScope handleScope(thread);
296             JSHandle<TaggedArray> properties;
297             JSHandle<JSObject> objHandle(thread, receiver);
298             JSHandle<JSTaggedValue> valueHandle(thread, value);
299             if (capacity == 0) {
300                 capacity = JSObject::MIN_PROPERTIES_LENGTH;
301                 properties = factory->NewTaggedArray(capacity);
302             } else {
303                 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
304                 properties = factory->CopyArray(arrayHandle, capacity,
305                                                 JSObject::ComputePropertyCapacity(capacity));
306             }
307             properties->Set(thread, index, valueHandle);
308             objHandle->SetProperties(thread, properties);
309             return;
310         }
311         array->Set(thread, index, value);
312         return;
313     }
314     StoreField(thread, receiver, value, handlerInfo);
315 }
316 
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)317 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
318                                                  JSTaggedValue handler)
319 {
320     INTERPRETER_TRACE(thread, StoreTransWithProto);
321     ASSERT(handler.IsTransWithProtoHandler());
322     TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
323     auto cellValue = transWithProtoHandler->GetProtoCell();
324     ASSERT(cellValue.IsProtoChangeMarker());
325     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
326     if (cell->GetHasChanged()) {
327         return JSTaggedValue::Hole();
328     }
329 
330     StoreWithTransition(thread, receiver, value, handler, true);
331     return JSTaggedValue::Undefined();
332 }
333 
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint32_t handler)334 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint32_t handler)
335 {
336     INTERPRETER_TRACE(thread, StoreField);
337     int index = HandlerBase::GetOffset(handler);
338     if (HandlerBase::IsInlinedProps(handler)) {
339         SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
340         return;
341     }
342     TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
343     ASSERT(index < static_cast<int>(array->GetLength()));
344     array->Set(thread, index, value);
345 }
346 
LoadFromField(JSObject * receiver,uint32_t handlerInfo)347 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint32_t handlerInfo)
348 {
349     int index = HandlerBase::GetOffset(handlerInfo);
350     if (HandlerBase::IsInlinedProps(handlerInfo)) {
351         return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
352     }
353     return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
354 }
355 
LoadGlobal(JSTaggedValue handler)356 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
357 {
358     ASSERT(handler.IsPropertyBox());
359     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
360     if (cell->IsInvalid()) {
361         return JSTaggedValue::Hole();
362     }
363     JSTaggedValue ret = cell->GetValue();
364     ASSERT(!ret.IsAccessorData());
365     return ret;
366 }
367 
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)368 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
369 {
370     INTERPRETER_TRACE(thread, StoreGlobal);
371     ASSERT(handler.IsPropertyBox());
372     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
373     if (cell->IsInvalid()) {
374         return JSTaggedValue::Hole();
375     }
376     ASSERT(!cell->GetValue().IsAccessorData());
377     cell->SetValue(thread, value);
378     return JSTaggedValue::Undefined();
379 }
380 
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)381 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
382 {
383     INTERPRETER_TRACE(thread, LoadPrototype);
384     ASSERT(handler.IsPrototypeHandler());
385     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
386     auto cellValue = prototypeHandler->GetProtoCell();
387     ASSERT(cellValue.IsProtoChangeMarker());
388     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
389     if (cell->GetHasChanged()) {
390         return JSTaggedValue::Hole();
391     }
392     auto holder = prototypeHandler->GetHolder();
393     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
394     return LoadICWithHandler(thread, receiver, holder, handlerInfo);
395 }
396 
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)397 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
398                                                           JSTaggedValue holder, JSTaggedValue handler)
399 {
400     INTERPRETER_TRACE(thread, LoadICWithHandler);
401     if (LIKELY(handler.IsInt())) {
402         auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
403         if (LIKELY(HandlerBase::IsField(handlerInfo))) {
404             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
405         }
406         if (HandlerBase::IsNonExist(handlerInfo)) {
407             return JSTaggedValue::Undefined();
408         }
409         ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
410         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
411         return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
412     }
413 
414     if (handler.IsPrototypeHandler()) {
415         return LoadPrototype(thread, receiver, handler);
416     }
417 
418     return LoadGlobal(handler);
419 }
420 
LoadElement(JSObject * receiver,JSTaggedValue key)421 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
422 {
423     auto index = TryToElementsIndex(key);
424     if (index < 0) {
425         return JSTaggedValue::Hole();
426     }
427     uint32_t elementIndex = static_cast<uint32_t>(index);
428     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
429     if (elements->GetLength() <= elementIndex) {
430         return JSTaggedValue::Hole();
431     }
432 
433     JSTaggedValue value = elements->Get(elementIndex);
434     // TaggedArray elements
435     return value;
436 }
437 
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)438 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
439                                           JSTaggedValue value, JSTaggedValue handler)
440 {
441     INTERPRETER_TRACE(thread, StoreElement);
442     auto index = TryToElementsIndex(key);
443     if (index < 0) {
444         return JSTaggedValue::Hole();
445     }
446     uint32_t elementIndex = static_cast<uint32_t>(index);
447     if (handler.IsInt()) {
448         auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
449         [[maybe_unused]] EcmaHandleScope handleScope(thread);
450         JSHandle<JSObject> receiverHandle(thread, receiver);
451         if (HandlerBase::IsJSArray(handlerInfo)) {
452             JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
453             if (receiveValue.IsJSCOWArray()) {
454                 // Copy on write array.
455                 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
456             }
457             JSArray *arr = JSArray::Cast(*receiverHandle);
458             uint32_t oldLength = arr->GetArrayLength();
459             if (elementIndex >= oldLength) {
460                 arr->SetArrayLength(thread, elementIndex + 1);
461             }
462         }
463         TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
464         uint32_t capacity = elements->GetLength();
465         if (elementIndex >= capacity) {
466             if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
467                 return JSTaggedValue::Hole();
468             }
469             JSHandle<JSTaggedValue> valueHandle(thread, value);
470             elements = *JSObject::GrowElementsCapacity(thread, receiverHandle,
471                                                        JSObject::ComputeElementCapacity(elementIndex + 1));
472             receiverHandle->SetElements(thread, JSTaggedValue(elements));
473             elements->Set(thread, elementIndex, valueHandle);
474             return JSTaggedValue::Undefined();
475         }
476         elements->Set(thread, elementIndex, value);
477     } else {
478         ASSERT(handler.IsPrototypeHandler());
479         PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
480         auto cellValue = prototypeHandler->GetProtoCell();
481         ASSERT(cellValue.IsProtoChangeMarker());
482         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
483         if (cell->GetHasChanged()) {
484             return JSTaggedValue::Hole();
485         }
486         JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
487         return StoreElement(thread, receiver, key, value, handlerInfo);
488     }
489     return JSTaggedValue::Undefined();
490 }
491 
TryToElementsIndex(JSTaggedValue key)492 ARK_INLINE int32_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
493 {
494     if (LIKELY(key.IsInt())) {
495         return key.GetInt();
496     }
497 
498     if (key.IsString()) {
499         uint32_t index = 0;
500         if (JSTaggedValue::StringToElementIndex(key, &index)) {
501             return static_cast<int32_t>(index);
502         }
503     }
504 
505     if (key.IsDouble()) {
506         double number = key.GetDouble();
507         auto integer = static_cast<int32_t>(number);
508         if (number == integer) {
509             return integer;
510         }
511     }
512 
513     return -1;
514 }
515 
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)516 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
517                                       JSTaggedValue key, uint32_t slotId, ICKind kind)
518 {
519     [[maybe_unused]] EcmaHandleScope handleScope(thread);
520     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
521     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
522     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
523     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
524     return icRuntime.LoadMiss(receiverHandle, keyHandle);
525 }
526 
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind)527 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
528                                        JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind)
529 {
530     [[maybe_unused]] EcmaHandleScope handleScope(thread);
531     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
532     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
533     auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
534     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
535     StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
536     return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle);
537 }
538 }  // namespace panda::ecmascript
539 
540 #endif  // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H_
541