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/js_tagged_value.h"
34 #include "ecmascript/object_factory-inl.h"
35 #include "ecmascript/runtime_call_id.h"
36 #include "ecmascript/js_primitive_ref.h"
37 
38 namespace panda::ecmascript {
LoadGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue globalValue, JSTaggedValue key, uint32_t slotId, bool tryLoad)39 JSTaggedValue ICRuntimeStub::LoadGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
40                                                 JSTaggedValue globalValue, JSTaggedValue key, uint32_t slotId,
41                                                 bool tryLoad)
42 {
43     INTERPRETER_TRACE(thread, LoadGlobalICByName);
44     JSTaggedValue handler = profileTypeInfo->Get(slotId);
45     if (handler.IsHeapObject()) {
46         auto result = LoadGlobal(handler);
47         if (!result.IsHole()) {
48             return result;
49         }
50     }
51     ICKind kind = tryLoad ? ICKind::NamedGlobalTryLoadIC : ICKind::NamedGlobalLoadIC;
52     return LoadMiss(thread, profileTypeInfo, globalValue, key, slotId, kind);
53 }
54 
StoreGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue globalValue, JSTaggedValue key, JSTaggedValue value, uint32_t slotId, bool tryStore)55 JSTaggedValue ICRuntimeStub::StoreGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
56                                                  JSTaggedValue globalValue, JSTaggedValue key,
57                                                  JSTaggedValue value, uint32_t slotId, bool tryStore)
58 {
59     INTERPRETER_TRACE(thread, StoreGlobalICByName);
60     JSTaggedValue handler = profileTypeInfo->Get(slotId);
61     if (handler.IsHeapObject()) {
62         auto result = StoreGlobal(thread, value, handler);
63         if (!result.IsHole()) {
64             return result;
65         }
66     }
67     ICKind kind = tryStore ? ICKind::NamedGlobalTryStoreIC : ICKind::NamedGlobalStoreIC;
68     return StoreMiss(thread, profileTypeInfo, globalValue, key, value, slotId, kind);
69 }
70 
CheckPolyHClass(JSTaggedValue cachedValue, JSHClass* hclass)71 JSTaggedValue ICRuntimeStub::CheckPolyHClass(JSTaggedValue cachedValue, JSHClass* hclass)
72 {
73     if (!cachedValue.IsWeak()) {
74         ASSERT(cachedValue.IsTaggedArray());
75         TaggedArray *array = TaggedArray::Cast(cachedValue.GetTaggedObject());
76         uint32_t length = array->GetLength();
77         for (uint32_t i = 0; i < length; i += 2) {  // 2 means one ic, two slot
78             auto result = array->Get(i);
79             if (!result.IsUndefined() && result.GetWeakReferent() == hclass) {
80                 return array->Get(i + 1);
81             }
82         }
83     }
84     return JSTaggedValue::Hole();
85 }
86 
TryLoadICByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue firstValue, JSTaggedValue secondValue)87 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByName(JSThread *thread, JSTaggedValue receiver,
88                                                         JSTaggedValue firstValue, JSTaggedValue secondValue)
89 {
90     INTERPRETER_TRACE(thread, TryLoadICByName);
91     if (LIKELY(receiver.IsHeapObject())) {
92         auto hclass = receiver.GetTaggedObject()->GetClass();
93         if (LIKELY(firstValue.GetWeakReferentUnChecked() == hclass)) {
94             return LoadICWithHandler(thread, receiver, receiver, secondValue);
95         }
96         JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
97         if (!cachedHandler.IsHole()) {
98             return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
99         }
100     } else if (receiver.IsNumber()) {
101         JSHandle<JSFunction> function(thread->GetEcmaVM()->GetGlobalEnv()->GetNumberFunction());
102         auto hclass = reinterpret_cast<JSHClass *>(function->GetProtoOrHClass().GetTaggedObject());
103         if (firstValue.GetWeakReferentUnChecked() == hclass) {
104             return LoadICWithHandler(thread, receiver, receiver, secondValue);
105         }
106     }
107     return JSTaggedValue::Hole();
108 }
109 
LoadICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)110 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
111                                                        JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
112 {
113     INTERPRETER_TRACE(thread, LoadICByName);
114     return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::NamedLoadIC);
115 }
116 
TryLoadICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue firstValue, JSTaggedValue secondValue)117 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
118                                                          JSTaggedValue firstValue, JSTaggedValue secondValue)
119 {
120     INTERPRETER_TRACE(thread, TryLoadICByValue);
121     if (receiver.IsHeapObject()) {
122         auto hclass = receiver.GetTaggedObject()->GetClass();
123         if (firstValue.GetWeakReferentUnChecked() == hclass) {
124             if (HandlerBase::IsNormalElement(secondValue.GetNumber())) {
125                 return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
126             } else if (HandlerBase::IsTypedArrayElement(secondValue.GetNumber())) {
127                 return LoadTypedArrayElement(thread, receiver, key);
128             }
129             ASSERT(HandlerBase::IsStringElement(secondValue.GetNumber()));
130             return LoadStringElement(thread, receiver, key);
131         }
132         // check ploy
133         if (secondValue.IsHole() && !firstValue.IsHole()) {
134             JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
135             return LoadICWithElementHandler(thread, receiver, cachedHandler, key);
136         }
137         // Check key
138         if (firstValue == key) {
139             JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
140             if (!cachedHandler.IsHole()) {
141                 return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
142             }
143         }
144     }
145     return JSTaggedValue::Hole();
146 }
147 
LoadICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)148 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
149                                                         JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
150 {
151     INTERPRETER_TRACE(thread, LoadICByValue);
152     return LoadValueMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::LoadIC);
153 }
154 
TryStoreICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue firstValue, JSTaggedValue secondValue, JSTaggedValue value)155 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByValue(JSThread *thread, JSTaggedValue receiver,
156                                                           JSTaggedValue key, JSTaggedValue firstValue,
157                                                           JSTaggedValue secondValue, JSTaggedValue value)
158 {
159     INTERPRETER_TRACE(thread, TryStoreICByValue);
160     if (receiver.IsHeapObject()) {
161         auto hclass = receiver.GetTaggedObject()->GetClass();
162         if (firstValue.GetWeakReferentUnChecked() == hclass) {
163             return StoreElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key, value, secondValue);
164         }
165         // Check key
166         if (firstValue == key) {
167             JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
168             if (!cachedHandler.IsHole()) {
169                 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
170             }
171         }
172     }
173 
174     return JSTaggedValue::Hole();
175 }
176 
StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value, uint32_t slotId)177 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
178                                                          JSTaggedValue receiver, JSTaggedValue key,
179                                                          JSTaggedValue value, uint32_t slotId)
180 {
181     INTERPRETER_TRACE(thread, StoreICByValue);
182     return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC);
183 }
184 
StoreOwnICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value, uint32_t slotId)185 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreOwnICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
186                                                             JSTaggedValue receiver, JSTaggedValue key,
187                                                             JSTaggedValue value, uint32_t slotId)
188 {
189     INTERPRETER_TRACE(thread, StoreOwnICByValue);
190     return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC, true);
191 }
192 
TryStoreICByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue firstValue, JSTaggedValue secondValue, JSTaggedValue value)193 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByName(JSThread *thread, JSTaggedValue receiver,
194                                                          JSTaggedValue firstValue, JSTaggedValue secondValue,
195                                                          JSTaggedValue value)
196 {
197     INTERPRETER_TRACE(thread, TryStoreICByName);
198     if (receiver.IsHeapObject()) {
199         auto hclass = receiver.GetTaggedObject()->GetClass();
200         if (firstValue.GetWeakReferentUnChecked() == hclass) {
201             return StoreICWithHandler(thread, receiver, receiver, value, secondValue);
202         }
203         JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
204         if (!cachedHandler.IsHole()) {
205             return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
206         }
207     }
208     return JSTaggedValue::Hole();
209 }
210 
StoreICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value, uint32_t slotId)211 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
212                                                         JSTaggedValue receiver, JSTaggedValue key,
213                                                         JSTaggedValue value, uint32_t slotId)
214 {
215     INTERPRETER_TRACE(thread, StoreICByName);
216     return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::NamedStoreIC);
217 }
218 
StoreICWithHandler(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue value, JSTaggedValue handler)219 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JSTaggedValue receiver,
220                                                            JSTaggedValue holder,
221                                                            JSTaggedValue value, JSTaggedValue handler)
222 {
223     INTERPRETER_TRACE(thread, StoreICWithHandler);
224     if (handler.IsInt()) {
225         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
226         if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
227             StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
228             return JSTaggedValue::Undefined();
229         }
230         bool isShared = HandlerBase::IsStoreShared(handlerInfo);
231         if (isShared) {
232             SharedFieldType fieldType { HandlerBase::GetFieldType(handlerInfo) };
233             bool hasAccessor = HandlerBase::IsAccessor(handlerInfo);
234             if (!hasAccessor && !ClassHelper::MatchFieldType(fieldType, value)) {
235                 THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty),
236                                             JSTaggedValue::Exception());
237             }
238             HandlerBase::ClearSharedStoreKind(handlerInfo);
239             return StoreICWithHandler(thread, receiver, holder, value,
240                                       JSTaggedValue::WrapUint64(handlerInfo));
241         }
242         ASSERT(HandlerBase::IsAccessor(handlerInfo));
243         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
244         return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
245     }
246     if (handler.IsTransitionHandler()) {
247         StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
248         return JSTaggedValue::Undefined();
249     }
250     if (handler.IsTransWithProtoHandler()) {
251         return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
252     }
253     if (handler.IsPrototypeHandler()) {
254         return StorePrototype(thread, receiver, value, handler);
255     }
256     if (handler.IsPropertyBox()) {
257         return StoreGlobal(thread, value, handler);
258     }
259     if (handler.IsStoreTSHandler()) {
260         return StoreWithTS(thread, receiver, value, handler);
261     }
262     return JSTaggedValue::Undefined();
263 }
264 
StorePrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value, JSTaggedValue handler)265 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
266                                             JSTaggedValue value, JSTaggedValue handler)
267 {
268     INTERPRETER_TRACE(thread, StorePrototype);
269     ASSERT(handler.IsPrototypeHandler());
270     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
271     if (!receiver.IsJSShared()) {
272         auto cellValue = prototypeHandler->GetProtoCell();
273         if (cellValue.IsNull()) {
274             return JSTaggedValue::Hole();
275         }
276         ASSERT(cellValue.IsProtoChangeMarker());
277         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
278         if (cell->GetHasChanged()) {
279             return JSTaggedValue::Hole();
280         }
281     }
282     auto holder = prototypeHandler->GetHolder();
283     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
284     return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
285 }
286 
StoreWithTS(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value, JSTaggedValue handler)287 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
288                                          JSTaggedValue value, JSTaggedValue handler)
289 {
290     INTERPRETER_TRACE(thread, StoreWithAOT);
291     ASSERT(handler.IsStoreTSHandler());
292     StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
293     auto cellValue = storeTSHandler->GetProtoCell();
294     ASSERT(cellValue.IsProtoChangeMarker());
295     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
296     if (cell->GetHasChanged()) {
297         return JSTaggedValue::Hole();
298     }
299     auto holder = storeTSHandler->GetHolder();
300     JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
301     auto handlerInfoInt = JSTaggedValue::UnwrapToUint64(handlerInfo);
302     if (HandlerBase::IsField(handlerInfoInt)) {
303         StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
304         return JSTaggedValue::Undefined();
305     }
306     ASSERT(HandlerBase::IsAccessor(handlerInfoInt));
307     auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
308     return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
309 }
310 
StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value, JSTaggedValue handler, bool withPrototype)311 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
312                                         JSTaggedValue handler, bool withPrototype)
313 {
314     INTERPRETER_TRACE(thread, StoreWithTransition);
315 
316     JSHClass *newHClass = nullptr;
317     uint64_t handlerInfo = 0;
318 
319     if (withPrototype) {
320         TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
321         newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
322         handlerInfo = JSTaggedValue::UnwrapToUint64(transWithProtoHandler->GetHandlerInfo());
323     } else {
324         TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
325         newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
326         handlerInfo = JSTaggedValue::UnwrapToUint64(transitionHandler->GetHandlerInfo());
327     }
328     JSHandle<JSHClass> newHClassHandle(thread, newHClass);
329     JSHandle<JSObject> objHandle(thread, receiver);
330     ElementsKind oldKind = receiver->GetJSHClass()->GetElementsKind();
331     JSHClass::RestoreElementsKindToGeneric(newHClass);
332     objHandle->SynchronizedSetClass(thread, newHClass);
333     JSObject::TryMigrateToGenericKindForJSObject(thread, objHandle, oldKind);
334 
335     ASSERT(HandlerBase::IsField(handlerInfo));
336 
337     if (!HandlerBase::IsInlinedProps(handlerInfo)) {
338         TaggedArray *array = TaggedArray::Cast(objHandle->GetProperties().GetTaggedObject());
339         int capacity = static_cast<int>(array->GetLength());
340         int index = HandlerBase::GetOffset(handlerInfo);
341         if (index >= capacity) {
342             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
343             [[maybe_unused]] EcmaHandleScope handleScope(thread);
344             JSHandle<TaggedArray> properties;
345             JSHandle<JSTaggedValue> valueHandle(thread, value);
346             if (capacity == 0) {
347                 capacity = JSObject::MIN_PROPERTIES_LENGTH;
348                 properties = factory->NewTaggedArray(capacity);
349             } else {
350                 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
351                 uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity();
352                 uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity,
353                                                                                maxNonInlinedFastPropsCapacity);
354                 properties = factory->CopyArray(arrayHandle, capacity, newLen);
355             }
356             properties->Set(thread, index, valueHandle);
357             objHandle->SetProperties(thread, properties);
358             return;
359         }
360         array->Set(thread, index, value);
361         return;
362     }
363     StoreField(thread, *objHandle, value, handlerInfo);
364 }
365 
StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value, JSTaggedValue handler)366 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
367                                                  JSTaggedValue handler)
368 {
369     INTERPRETER_TRACE(thread, StoreTransWithProto);
370     ASSERT(handler.IsTransWithProtoHandler());
371     ASSERT(!receiver->GetClass()->IsJSShared());
372     TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
373     auto cellValue = transWithProtoHandler->GetProtoCell();
374     ASSERT(cellValue.IsProtoChangeMarker());
375     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
376     if (cell->GetHasChanged()) {
377         return JSTaggedValue::Hole();
378     }
379 
380     StoreWithTransition(thread, receiver, value, handler, true);
381     return JSTaggedValue::Undefined();
382 }
383 
StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint64_t handler)384 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint64_t handler)
385 {
386     INTERPRETER_TRACE(thread, StoreField);
387     int index = HandlerBase::GetOffset(handler);
388     if (HandlerBase::IsInlinedProps(handler)) {
389         SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
390         return;
391     }
392     TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
393     ASSERT(index < static_cast<int>(array->GetLength()));
394     array->Set(thread, index, value);
395 }
396 
LoadFromField(JSObject *receiver, uint64_t handlerInfo)397 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint64_t handlerInfo)
398 {
399     int index = HandlerBase::GetOffset(handlerInfo);
400     if (HandlerBase::IsInlinedProps(handlerInfo)) {
401         return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
402     }
403     return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
404 }
405 
LoadGlobal(JSTaggedValue handler)406 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
407 {
408     ASSERT(handler.IsPropertyBox());
409     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
410     if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
411         return JSTaggedValue::Hole();
412     }
413     JSTaggedValue ret = cell->GetValue();
414     ASSERT(!ret.IsAccessorData());
415     return ret;
416 }
417 
StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)418 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
419 {
420     INTERPRETER_TRACE(thread, StoreGlobal);
421     ASSERT(handler.IsPropertyBox());
422     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
423     if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
424         return JSTaggedValue::Hole();
425     }
426     ASSERT(!cell->GetValue().IsAccessorData());
427     cell->SetValue(thread, value);
428     return JSTaggedValue::Undefined();
429 }
430 
LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)431 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
432 {
433     INTERPRETER_TRACE(thread, LoadPrototype);
434     ASSERT(handler.IsPrototypeHandler());
435     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
436     if (!receiver.IsJSShared()) {
437         auto cellValue = prototypeHandler->GetProtoCell();
438         ASSERT(cellValue.IsProtoChangeMarker());
439         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
440         if (cell->GetHasChanged()) {
441             return JSTaggedValue::Hole();
442         }
443     }
444     auto holder = prototypeHandler->GetHolder();
445     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
446     return LoadICWithHandler(thread, receiver, holder, handlerInfo);
447 }
448 
LoadICWithHandler(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue handler)449 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
450                                                           JSTaggedValue holder, JSTaggedValue handler)
451 {
452     INTERPRETER_TRACE(thread, LoadICWithHandler);
453     if (LIKELY(handler.IsInt())) {
454         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
455         if (LIKELY(HandlerBase::IsField(handlerInfo))) {
456             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
457         }
458         if (HandlerBase::IsString(handlerInfo) || HandlerBase::IsNumber(handlerInfo)) {
459             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
460         }
461         if (HandlerBase::IsNonExist(handlerInfo)) {
462             return JSTaggedValue::Undefined();
463         }
464         if (HandlerBase::IsStringLength(handlerInfo)) {
465             return JSTaggedNumber((EcmaStringAccessor(EcmaString::Cast(holder)).GetLength()));
466         }
467         ASSERT(HandlerBase::IsAccessor(handlerInfo));
468         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
469         return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
470     }
471 
472     if (handler.IsPrototypeHandler()) {
473         return LoadPrototype(thread, receiver, handler);
474     }
475 
476     return LoadGlobal(handler);
477 }
478 
LoadICWithElementHandler(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler, JSTaggedValue key)479 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *thread, JSTaggedValue receiver,
480     JSTaggedValue handler, JSTaggedValue key)
481 {
482     if (LIKELY(handler.IsInt())) {
483         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
484         if (HandlerBase::IsNormalElement(handlerInfo)) {
485             return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
486         } else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
487             return LoadTypedArrayElement(thread, receiver, key);
488         }
489         ASSERT(HandlerBase::IsStringElement(handlerInfo));
490         return LoadStringElement(thread, receiver, key);
491     }
492     return JSTaggedValue::Hole();
493 }
494 
LoadElement(JSObject *receiver, JSTaggedValue key)495 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
496 {
497     auto index = TryToElementsIndex(key);
498     if (index < 0) {
499         return JSTaggedValue::Hole();
500     }
501     uint32_t elementIndex = static_cast<uint32_t>(index);
502     if (ElementAccessor::GetElementsLength(receiver) <= elementIndex) {
503         return JSTaggedValue::Hole();
504     }
505 
506     JSTaggedValue value = ElementAccessor::Get(receiver, elementIndex);
507     // TaggedArray elements
508     return value;
509 }
510 
LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)511 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
512 {
513     auto index = TryToElementsIndex(key);
514     if (index < 0) {
515         return JSTaggedValue::Hole();
516     }
517     uint32_t elementIndex = static_cast<uint32_t>(index);
518     uint16_t tmpChar = 0;
519     {
520         JSHandle<EcmaString> strHandle(thread, receiver);
521         JSHandle<EcmaString> strFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), strHandle));
522         if (EcmaStringAccessor(strFlat).GetLength() <= elementIndex) {
523             return JSTaggedValue::Hole();
524         }
525         tmpChar = EcmaStringAccessor(strFlat).Get(elementIndex);
526     }
527     auto factory = thread->GetEcmaVM()->GetFactory();
528     JSHandle<JSTaggedValue> value(factory->NewFromUtf16(&tmpChar, 1));
529     return value.GetTaggedValue();
530 }
531 
LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)532 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
533                                                               JSTaggedValue key)
534 {
535     auto index = TryToElementsIndex(key);
536     if (index < 0) {
537         return JSTaggedValue::Hole();
538     }
539     auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
540     uint32_t arrLen = typedarrayObj->GetArrayLength();
541     if (index >= arrLen) {
542         return JSTaggedValue::Hole();
543     }
544     JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
545     return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, type);
546 }
547 
StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key, JSTaggedValue value, JSTaggedValue handler)548 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
549                                           JSTaggedValue value, JSTaggedValue handler)
550 {
551     INTERPRETER_TRACE(thread, StoreElement);
552     auto index = TryToElementsIndex(key);
553     if (index < 0) {
554         return JSTaggedValue::Hole();
555     }
556     uint32_t elementIndex = static_cast<uint32_t>(index);
557     if (handler.IsInt()) {
558         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
559         [[maybe_unused]] EcmaHandleScope handleScope(thread);
560         JSHandle<JSObject> receiverHandle(thread, receiver);
561         JSHandle<JSTaggedValue> valueHandle(thread, value);
562         if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
563             return StoreTypedArrayElement(thread, JSTaggedValue::Cast(receiver), key, value);
564         } else if (HandlerBase::IsJSArray(handlerInfo)) {
565             JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
566             if (receiveValue.IsJSCOWArray()) {
567                 // Copy on write array.
568                 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
569             }
570             JSArray *arr = JSArray::Cast(*receiverHandle);
571             uint32_t oldLength = arr->GetArrayLength();
572             if (elementIndex >= oldLength) {
573                 arr->SetArrayLength(thread, elementIndex + 1);
574             }
575         }
576         TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
577         uint32_t capacity = elements->GetLength();
578         if (elementIndex >= capacity) {
579             if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
580                 return JSTaggedValue::Hole();
581             }
582             elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
583             receiverHandle->SetElements(thread, JSTaggedValue(elements));
584             elements->Set(thread, elementIndex, valueHandle);
585             return JSTaggedValue::Undefined();
586         }
587         elements->Set(thread, elementIndex, valueHandle);
588     } else {
589         ASSERT(handler.IsPrototypeHandler());
590         if (receiver->GetClass()->IsJSShared()) {
591             THROW_TYPE_ERROR_AND_RETURN(thread,
592                 GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception());
593         }
594         PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
595         auto cellValue = prototypeHandler->GetProtoCell();
596         ASSERT(cellValue.IsProtoChangeMarker());
597         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
598         if (cell->GetHasChanged()) {
599             return JSTaggedValue::Hole();
600         }
601         JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
602         return StoreElement(thread, receiver, key, value, handlerInfo);
603     }
604     return JSTaggedValue::Undefined();
605 }
606 
StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value)607 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
608                                                                JSTaggedValue key, JSTaggedValue value)
609 {
610     auto index = TryToElementsIndex(key);
611     if (index < 0) {
612         return JSTaggedValue::Hole();
613     }
614     auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
615     uint32_t arrLen = typedarrayObj->GetArrayLength();
616     if (index >= arrLen) {
617         return JSTaggedValue::Hole();
618     }
619     JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
620     return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, type);
621 }
622 
TryToElementsIndex(JSTaggedValue key)623 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
624 {
625     if (LIKELY(key.IsInt())) {
626         return key.GetInt();
627     }
628 
629     if (key.IsString()) {
630         uint32_t index = 0;
631         if (JSTaggedValue::StringToElementIndex(key, &index)) {
632             return static_cast<int64_t>(index);
633         }
634     }
635 
636     if (key.IsDouble()) {
637         double number = key.GetDouble();
638         auto integer = static_cast<int32_t>(number);
639         if (number == integer) {
640             return integer;
641         }
642     }
643 
644     return -1;
645 }
646 
LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId, ICKind kind)647 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
648                                       JSTaggedValue key, uint32_t slotId, ICKind kind)
649 {
650     [[maybe_unused]] EcmaHandleScope handleScope(thread);
651     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
652     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
653     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
654     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
655     return icRuntime.LoadMiss(receiverHandle, keyHandle);
656 }
657 
LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId, ICKind kind)658 JSTaggedValue ICRuntimeStub::LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
659                                            JSTaggedValue key, uint32_t slotId, ICKind kind)
660 {
661     [[maybe_unused]] EcmaHandleScope handleScope(thread);
662     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
663     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
664     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
665     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
666     return icRuntime.LoadValueMiss(receiverHandle, keyHandle);
667 }
668 
StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)669 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
670                                        JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)
671 {
672     [[maybe_unused]] EcmaHandleScope handleScope(thread);
673     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
674     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
675     auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
676     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
677     StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
678     return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle, isOwn);
679 }
680 }  // namespace panda::ecmascript
681 
682 #endif  // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
683