• 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 #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(thread, 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         HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
227         if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
228             StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
229             return JSTaggedValue::Undefined();
230         }
231         bool isShared = HandlerBase::IsStoreShared(handlerInfo);
232         if (isShared) {
233             SharedFieldType fieldType { HandlerBase::GetFieldType(handlerInfo) };
234             bool hasAccessor = HandlerBase::IsAccessor(handlerInfo);
235             if (!hasAccessor) {
236                 if (!ClassHelper::MatchFieldType(fieldType, value)) {
237                     [[maybe_unused]] EcmaHandleScope handleScope(thread);
238                     THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty),
239                                                 JSTaggedValue::Exception());
240                 }
241                 if (value.IsTreeString()) {
242                     [[maybe_unused]] EcmaHandleScope handleScope(thread);
243                     JSHandle<JSTaggedValue> objHandle(thread, receiver);
244                     JSHandle<JSTaggedValue> holderHandle(thread, holder);
245                     JSHandle<JSTaggedValue> valueHandle(thread, value);
246                     value = JSTaggedValue::PublishSharedValue(thread, valueHandle).GetTaggedValue();
247                     receiver = objHandle.GetTaggedValue();
248                     holder = holderHandle.GetTaggedValue();
249                 }
250             }
251             HandlerBase::ClearSharedStoreKind(handlerInfo);
252             return StoreICWithHandler(thread, receiver, holder, value,
253                                       JSTaggedValue::WrapUint64(handlerInfo));
254         }
255         ASSERT(HandlerBase::IsAccessor(handlerInfo));
256         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
257         return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
258     }
259     if (handler.IsTransitionHandler()) {
260         StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
261         return JSTaggedValue::Undefined();
262     }
263     if (handler.IsTransWithProtoHandler()) {
264         return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
265     }
266     if (handler.IsPrototypeHandler()) {
267         return StorePrototype(thread, receiver, value, handler);
268     }
269     if (handler.IsPropertyBox()) {
270         return StoreGlobal(thread, value, handler);
271     }
272     if (handler.IsStoreAOTHandler()) {
273         return StoreWithTS(thread, receiver, value, handler);
274     }
275     return JSTaggedValue::Undefined();
276 }
277 
StorePrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)278 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
279                                             JSTaggedValue value, JSTaggedValue handler)
280 {
281     INTERPRETER_TRACE(thread, StorePrototype);
282     ASSERT(handler.IsPrototypeHandler());
283     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
284     if (!receiver.IsJSShared()) {
285         auto cellValue = prototypeHandler->GetProtoCell();
286         if (cellValue.IsNull()) {
287             return JSTaggedValue::Hole();
288         }
289         ASSERT(cellValue.IsProtoChangeMarker());
290         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
291         if (cell->GetHasChanged()) {
292             return JSTaggedValue::Hole();
293         }
294     }
295     auto holder = prototypeHandler->GetHolder();
296     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
297     return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
298 }
299 
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)300 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
301                                          JSTaggedValue value, JSTaggedValue handler)
302 {
303     INTERPRETER_TRACE(thread, StoreWithAOT);
304     ASSERT(handler.IsStoreAOTHandler());
305     StoreAOTHandler *storeAOTHandler = StoreAOTHandler::Cast(handler.GetTaggedObject());
306     auto cellValue = storeAOTHandler->GetProtoCell();
307     if (cellValue == JSTaggedValue::Undefined()) {
308         return JSTaggedValue::Hole();
309     }
310     ASSERT(cellValue.IsProtoChangeMarker());
311     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
312     if (cell->GetHasChanged()) {
313         return JSTaggedValue::Hole();
314     }
315     auto holder = storeAOTHandler->GetHolder();
316     JSTaggedValue handlerInfo = storeAOTHandler->GetHandlerInfo();
317     auto handlerInfoInt = JSTaggedValue::UnwrapToUint64(handlerInfo);
318     if (HandlerBase::IsField(handlerInfoInt)) {
319         StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
320         return JSTaggedValue::Undefined();
321     }
322     ASSERT(HandlerBase::IsAccessor(handlerInfoInt));
323     auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
324     return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
325 }
326 
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)327 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
328                                         JSTaggedValue handler, bool withPrototype)
329 {
330     INTERPRETER_TRACE(thread, StoreWithTransition);
331 
332     JSHClass *newHClass = nullptr;
333     uint64_t handlerInfo = 0;
334 
335     if (withPrototype) {
336         TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
337         newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
338         handlerInfo = JSTaggedValue::UnwrapToUint64(transWithProtoHandler->GetHandlerInfo());
339     } else {
340         TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
341         newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
342         handlerInfo = JSTaggedValue::UnwrapToUint64(transitionHandler->GetHandlerInfo());
343     }
344     JSHandle<JSHClass> newHClassHandle(thread, newHClass);
345     JSHandle<JSHClass> oldHClassHandle(thread, receiver->GetJSHClass());
346     if (newHClassHandle->IsPrototype()) {
347         newHClassHandle->SetProtoChangeDetails(thread, oldHClassHandle->GetProtoChangeDetails());
348     }
349     JSHandle<JSObject> objHandle(thread, receiver);
350     ElementsKind oldKind = receiver->GetJSHClass()->GetElementsKind();
351     JSHClass::RestoreElementsKindToGeneric(newHClass);
352     objHandle->SynchronizedSetClass(thread, newHClass);
353     JSObject::TryMigrateToGenericKindForJSObject(thread, objHandle, oldKind);
354 
355     ASSERT(HandlerBase::IsField(handlerInfo));
356 
357     if (!HandlerBase::IsInlinedProps(handlerInfo)) {
358         TaggedArray *array = TaggedArray::Cast(objHandle->GetProperties().GetTaggedObject());
359         int capacity = static_cast<int>(array->GetLength());
360         int index = HandlerBase::GetOffset(handlerInfo);
361         if (index >= capacity) {
362             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
363             [[maybe_unused]] EcmaHandleScope handleScope(thread);
364             JSHandle<TaggedArray> properties;
365             JSHandle<JSTaggedValue> valueHandle(thread, value);
366             if (capacity == 0) {
367                 capacity = JSObject::MIN_PROPERTIES_LENGTH;
368                 properties = factory->NewTaggedArray(capacity);
369             } else {
370                 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
371                 uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity();
372                 uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity,
373                                                                                maxNonInlinedFastPropsCapacity);
374                 properties = factory->CopyArray(arrayHandle, capacity, newLen);
375             }
376             properties->Set(thread, index, valueHandle);
377             objHandle->SetProperties(thread, properties);
378             return;
379         }
380         array->Set(thread, index, value);
381         return;
382     }
383     StoreField(thread, *objHandle, value, handlerInfo);
384 }
385 
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)386 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
387                                                  JSTaggedValue handler)
388 {
389     INTERPRETER_TRACE(thread, StoreTransWithProto);
390     ASSERT(handler.IsTransWithProtoHandler());
391     ASSERT(!receiver->GetClass()->IsJSShared());
392     TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
393     auto cellValue = transWithProtoHandler->GetProtoCell();
394     if (cellValue == JSTaggedValue::Undefined()) {
395         return JSTaggedValue::Hole();
396     }
397     ASSERT(cellValue.IsProtoChangeMarker());
398     ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
399     if (cell->GetHasChanged()) {
400         return JSTaggedValue::Hole();
401     }
402 
403     StoreWithTransition(thread, receiver, value, handler, true);
404     return JSTaggedValue::Undefined();
405 }
406 
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint64_t handler)407 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint64_t handler)
408 {
409     INTERPRETER_TRACE(thread, StoreField);
410     int index = HandlerBase::GetOffset(handler);
411     if (HandlerBase::IsInlinedProps(handler)) {
412         SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
413         return;
414     }
415     TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
416     ASSERT(index < static_cast<int>(array->GetLength()));
417     array->Set(thread, index, value);
418 }
419 
LoadFromField(JSObject * receiver,uint64_t handlerInfo)420 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint64_t handlerInfo)
421 {
422     int index = HandlerBase::GetOffset(handlerInfo);
423     if (HandlerBase::IsInlinedProps(handlerInfo)) {
424         return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
425     }
426     return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
427 }
428 
LoadGlobal(JSTaggedValue handler)429 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
430 {
431     ASSERT(handler.IsPropertyBox());
432     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
433     if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
434         return JSTaggedValue::Hole();
435     }
436     JSTaggedValue ret = cell->GetValue();
437     ASSERT(!ret.IsAccessorData());
438     return ret;
439 }
440 
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)441 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
442 {
443     INTERPRETER_TRACE(thread, StoreGlobal);
444     ASSERT(handler.IsPropertyBox());
445     PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
446     if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
447         return JSTaggedValue::Hole();
448     }
449     ASSERT(!cell->GetValue().IsAccessorData());
450     cell->SetValue(thread, value);
451     return JSTaggedValue::Undefined();
452 }
453 
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)454 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
455 {
456     INTERPRETER_TRACE(thread, LoadPrototype);
457     ASSERT(handler.IsPrototypeHandler());
458     PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
459     auto holder = prototypeHandler->GetHolder();
460     if (!receiver.IsJSShared()) {
461         auto cellValue = prototypeHandler->GetProtoCell();
462         if (cellValue == JSTaggedValue::Undefined()) {
463             return JSTaggedValue::Hole();
464         }
465         ASSERT(cellValue.IsProtoChangeMarker());
466         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
467         if (cell->GetHasChanged()) {
468             return JSTaggedValue::Hole();
469         }
470 
471         // For "Not Found" case (holder equals Undefined()),
472         // we should ensure that both GetNotFoundHasChanged() and GetHasChanged() return false.
473         if (holder == JSTaggedValue::Undefined()) {
474             if (cell->GetNotFoundHasChanged()) {
475                 return JSTaggedValue::Hole();
476             }
477             return JSTaggedValue::Undefined();
478         }
479     }
480 
481     JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
482     return LoadICWithHandler(thread, receiver, holder, handlerInfo);
483 }
484 
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)485 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
486                                                           JSTaggedValue holder, JSTaggedValue handler)
487 {
488     INTERPRETER_TRACE(thread, LoadICWithHandler);
489     if (LIKELY(handler.IsInt())) {
490         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
491         HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
492         if (LIKELY(HandlerBase::IsField(handlerInfo))) {
493             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
494         }
495         if (HandlerBase::IsString(handlerInfo) || HandlerBase::IsNumber(handlerInfo)) {
496             return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
497         }
498 
499         // For the special "Not Found" case we may generate ic by "LoadHandler::LoadProperty".
500         // In this situation, you can trust ic without ChangeMarker.
501         if (HandlerBase::IsNonExist(handlerInfo)) {
502             return JSTaggedValue::Undefined();
503         }
504 
505         if (HandlerBase::IsStringLength(handlerInfo)) {
506             return JSTaggedNumber((EcmaStringAccessor(EcmaString::Cast(holder)).GetLength()));
507         }
508         ASSERT(HandlerBase::IsAccessor(handlerInfo));
509         auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
510         return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
511     }
512 
513     if (handler.IsPrototypeHandler()) {
514         return LoadPrototype(thread, receiver, handler);
515     }
516 
517     return LoadGlobal(handler);
518 }
519 
LoadICWithElementHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler,JSTaggedValue key)520 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *thread, JSTaggedValue receiver,
521     JSTaggedValue handler, JSTaggedValue key)
522 {
523     if (LIKELY(handler.IsInt())) {
524         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
525         HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
526         if (HandlerBase::IsNormalElement(handlerInfo)) {
527             return LoadElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key);
528         } else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
529             return LoadTypedArrayElement(thread, receiver, key);
530         }
531         ASSERT(HandlerBase::IsStringElement(handlerInfo));
532         return LoadStringElement(thread, receiver, key);
533     }
534     return JSTaggedValue::Hole();
535 }
536 
LoadElement(JSThread * thread,JSObject * receiver,JSTaggedValue key)537 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSThread *thread, JSObject *receiver, JSTaggedValue key)
538 {
539     auto index = TryToElementsIndex(key);
540     if (index < 0) {
541         return JSTaggedValue::Hole();
542     }
543     uint32_t elementIndex = static_cast<uint32_t>(index);
544     if (ElementAccessor::GetElementsLength(receiver) <= elementIndex) {
545         return JSTaggedValue::Hole();
546     }
547 
548     JSTaggedValue value = ElementAccessor::Get(thread, receiver, elementIndex);
549     // TaggedArray elements
550     return value;
551 }
552 
LoadStringElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)553 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
554 {
555     auto index = TryToElementsIndex(key);
556     if (index < 0) {
557         return JSTaggedValue::Hole();
558     }
559     uint32_t elementIndex = static_cast<uint32_t>(index);
560     uint16_t tmpChar = 0;
561     {
562         JSHandle<EcmaString> strHandle(thread, receiver);
563         JSHandle<EcmaString> strFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), strHandle));
564         if (EcmaStringAccessor(strFlat).GetLength() <= elementIndex) {
565             return JSTaggedValue::Hole();
566         }
567         tmpChar = EcmaStringAccessor(strFlat).Get(elementIndex);
568     }
569     auto factory = thread->GetEcmaVM()->GetFactory();
570     JSHandle<JSTaggedValue> value(factory->NewFromUtf16(&tmpChar, 1));
571     return value.GetTaggedValue();
572 }
573 
LoadTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)574 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
575                                                               JSTaggedValue key)
576 {
577     auto index = TryToElementsIndex(key);
578     if (index < 0) {
579         return JSTaggedValue::Hole();
580     }
581     auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
582     uint32_t arrLen = typedarrayObj->GetArrayLength();
583     if (index >= arrLen) {
584         return JSTaggedValue::Hole();
585     }
586     JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
587     return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, type);
588 }
589 
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)590 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
591                                           JSTaggedValue value, JSTaggedValue handler)
592 {
593     INTERPRETER_TRACE(thread, StoreElement);
594     auto index = TryToElementsIndex(key);
595     if (index < 0) {
596         return JSTaggedValue::Hole();
597     }
598     uint32_t elementIndex = static_cast<uint32_t>(index);
599     if (handler.IsInt()) {
600         auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
601         HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
602         [[maybe_unused]] EcmaHandleScope handleScope(thread);
603         JSHandle<JSObject> receiverHandle(thread, receiver);
604         JSHandle<JSTaggedValue> valueHandle(thread, value);
605         if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
606             return StoreTypedArrayElement(thread, JSTaggedValue::Cast(receiver), key, value);
607         } else if (HandlerBase::IsJSArray(handlerInfo)) {
608             JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
609             if (receiveValue.IsJSCOWArray()) {
610                 // Copy on write array.
611                 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
612             }
613             JSArray *arr = JSArray::Cast(*receiverHandle);
614             uint32_t oldLength = arr->GetArrayLength();
615             if (elementIndex >= oldLength) {
616                 arr->SetArrayLength(thread, elementIndex + 1);
617             }
618         }
619         TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
620         uint32_t capacity = elements->GetLength();
621         if (elementIndex >= capacity) {
622             if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
623                 return JSTaggedValue::Hole();
624             }
625             elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
626             receiverHandle->SetElements(thread, JSTaggedValue(elements));
627             elements->Set(thread, elementIndex, valueHandle);
628             return JSTaggedValue::Undefined();
629         }
630         elements->Set(thread, elementIndex, valueHandle);
631     } else {
632         ASSERT(handler.IsPrototypeHandler());
633         if (receiver->GetClass()->IsJSShared()) {
634             THROW_TYPE_ERROR_AND_RETURN(thread,
635                 GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception());
636         }
637         PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
638         auto cellValue = prototypeHandler->GetProtoCell();
639         if (cellValue == JSTaggedValue::Undefined()) {
640             return JSTaggedValue::Hole();
641         }
642         ASSERT(cellValue.IsProtoChangeMarker());
643         ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
644         if (cell->GetHasChanged()) {
645             return JSTaggedValue::Hole();
646         }
647         JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
648         return StoreElement(thread, receiver, key, value, handlerInfo);
649     }
650     return JSTaggedValue::Undefined();
651 }
652 
StoreTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)653 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
654                                                                JSTaggedValue key, JSTaggedValue value)
655 {
656     auto index = TryToElementsIndex(key);
657     if (index < 0) {
658         return JSTaggedValue::Hole();
659     }
660     auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
661     uint32_t arrLen = typedarrayObj->GetArrayLength();
662     if (index >= arrLen) {
663         return JSTaggedValue::Hole();
664     }
665     JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
666     return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, type);
667 }
668 
TryToElementsIndex(JSTaggedValue key)669 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
670 {
671     if (LIKELY(key.IsInt())) {
672         return key.GetInt();
673     }
674 
675     if (key.IsString()) {
676         uint32_t index = 0;
677         if (JSTaggedValue::StringToElementIndex(key, &index)) {
678             return static_cast<int64_t>(index);
679         }
680     }
681 
682     if (key.IsDouble()) {
683         double number = key.GetDouble();
684         auto integer = static_cast<int32_t>(number);
685         if (number == integer) {
686             return integer;
687         }
688     }
689 
690     return -1;
691 }
692 
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)693 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
694                                       JSTaggedValue key, uint32_t slotId, ICKind kind)
695 {
696     [[maybe_unused]] EcmaHandleScope handleScope(thread);
697     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
698     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
699     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
700     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
701     return icRuntime.LoadMiss(receiverHandle, keyHandle);
702 }
703 
LoadValueMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)704 JSTaggedValue ICRuntimeStub::LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
705                                            JSTaggedValue key, uint32_t slotId, ICKind kind)
706 {
707     [[maybe_unused]] EcmaHandleScope handleScope(thread);
708     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
709     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
710     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
711     LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
712     return icRuntime.LoadValueMiss(receiverHandle, keyHandle);
713 }
714 
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind,bool isOwn)715 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
716                                        JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)
717 {
718     [[maybe_unused]] EcmaHandleScope handleScope(thread);
719     auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
720     auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
721     auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
722     auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
723     StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
724     return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle, isOwn);
725 }
726 }  // namespace panda::ecmascript
727 
728 #endif  // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
729