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