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