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/object_factory-inl.h"
34 #include "ecmascript/runtime_call_id.h"
35
36 namespace panda::ecmascript {
LoadGlobalICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue globalValue,JSTaggedValue key,uint32_t slotId,bool tryLoad)37 JSTaggedValue ICRuntimeStub::LoadGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
38 JSTaggedValue globalValue, JSTaggedValue key, uint32_t slotId,
39 bool tryLoad)
40 {
41 INTERPRETER_TRACE(thread, LoadGlobalICByName);
42 JSTaggedValue handler = profileTypeInfo->Get(slotId);
43 if (handler.IsHeapObject()) {
44 auto result = LoadGlobal(handler);
45 if (!result.IsHole()) {
46 return result;
47 }
48 }
49 ICKind kind = tryLoad ? ICKind::NamedGlobalTryLoadIC : ICKind::NamedGlobalLoadIC;
50 return LoadMiss(thread, profileTypeInfo, globalValue, key, slotId, kind);
51 }
52
StoreGlobalICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue globalValue,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,bool tryStore)53 JSTaggedValue ICRuntimeStub::StoreGlobalICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
54 JSTaggedValue globalValue, JSTaggedValue key,
55 JSTaggedValue value, uint32_t slotId, bool tryStore)
56 {
57 INTERPRETER_TRACE(thread, StoreGlobalICByName);
58 JSTaggedValue handler = profileTypeInfo->Get(slotId);
59 if (handler.IsHeapObject()) {
60 auto result = StoreGlobal(thread, value, handler);
61 if (!result.IsHole()) {
62 return result;
63 }
64 }
65 ICKind kind = tryStore ? ICKind::NamedGlobalTryStoreIC : ICKind::NamedGlobalStoreIC;
66 return StoreMiss(thread, profileTypeInfo, globalValue, key, value, slotId, kind);
67 }
68
CheckPolyHClass(JSTaggedValue cachedValue,JSHClass * hclass)69 JSTaggedValue ICRuntimeStub::CheckPolyHClass(JSTaggedValue cachedValue, JSHClass* hclass)
70 {
71 if (!cachedValue.IsWeak()) {
72 ASSERT(cachedValue.IsTaggedArray());
73 TaggedArray *array = TaggedArray::Cast(cachedValue.GetTaggedObject());
74 uint32_t length = array->GetLength();
75 for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
76 auto result = array->Get(i);
77 if (!result.IsUndefined() && result.GetWeakReferent() == hclass) {
78 return array->Get(i + 1);
79 }
80 }
81 }
82 return JSTaggedValue::Hole();
83 }
84
TryLoadICByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue firstValue,JSTaggedValue secondValue)85 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByName(JSThread *thread, JSTaggedValue receiver,
86 JSTaggedValue firstValue, JSTaggedValue secondValue)
87 {
88 INTERPRETER_TRACE(thread, TryLoadICByName);
89 if (LIKELY(receiver.IsHeapObject())) {
90 auto hclass = receiver.GetTaggedObject()->GetClass();
91 if (LIKELY(firstValue.GetWeakReferentUnChecked() == hclass)) {
92 return LoadICWithHandler(thread, receiver, receiver, secondValue);
93 }
94 JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
95 if (!cachedHandler.IsHole()) {
96 return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
97 }
98 }
99 return JSTaggedValue::Hole();
100 }
101
LoadICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)102 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
103 JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
104 {
105 INTERPRETER_TRACE(thread, LoadICByName);
106 return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::NamedLoadIC);
107 }
108
TryLoadICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue)109 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
110 JSTaggedValue firstValue, JSTaggedValue secondValue)
111 {
112 INTERPRETER_TRACE(thread, TryLoadICByValue);
113 if (receiver.IsHeapObject()) {
114 auto hclass = receiver.GetTaggedObject()->GetClass();
115 if (firstValue.GetWeakReferentUnChecked() == hclass) {
116 ASSERT(HandlerBase::IsElement(secondValue.GetInt()));
117 return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
118 }
119 // Check key
120 if (firstValue == key) {
121 JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
122 if (!cachedHandler.IsHole()) {
123 return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
124 }
125 }
126 }
127 return JSTaggedValue::Hole();
128 }
129
LoadICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)130 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
131 JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
132 {
133 INTERPRETER_TRACE(thread, LoadICByValue);
134 return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::LoadIC);
135 }
136
TryStoreICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)137 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByValue(JSThread *thread, JSTaggedValue receiver,
138 JSTaggedValue key, JSTaggedValue firstValue,
139 JSTaggedValue secondValue, JSTaggedValue value)
140 {
141 INTERPRETER_TRACE(thread, TryStoreICByValue);
142 if (receiver.IsHeapObject()) {
143 auto hclass = receiver.GetTaggedObject()->GetClass();
144 if (firstValue.GetWeakReferentUnChecked() == hclass) {
145 return StoreElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key, value, secondValue);
146 }
147 // Check key
148 if (firstValue == key) {
149 JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
150 if (!cachedHandler.IsHole()) {
151 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
152 }
153 }
154 }
155
156 return JSTaggedValue::Hole();
157 }
158
StoreICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)159 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
160 JSTaggedValue receiver, JSTaggedValue key,
161 JSTaggedValue value, uint32_t slotId)
162 {
163 INTERPRETER_TRACE(thread, StoreICByValue);
164 return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC);
165 }
166
TryStoreICByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)167 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByName(JSThread *thread, JSTaggedValue receiver,
168 JSTaggedValue firstValue, JSTaggedValue secondValue,
169 JSTaggedValue value)
170 {
171 INTERPRETER_TRACE(thread, TryStoreICByName);
172 if (receiver.IsHeapObject()) {
173 auto hclass = receiver.GetTaggedObject()->GetClass();
174 if (firstValue.GetWeakReferentUnChecked() == hclass) {
175 return StoreICWithHandler(thread, receiver, receiver, value, secondValue);
176 }
177 JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
178 if (!cachedHandler.IsHole()) {
179 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
180 }
181 }
182 return JSTaggedValue::Hole();
183 }
184
StoreICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)185 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
186 JSTaggedValue receiver, JSTaggedValue key,
187 JSTaggedValue value, uint32_t slotId)
188 {
189 INTERPRETER_TRACE(thread, StoreICByName);
190 return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::NamedStoreIC);
191 }
192
StoreICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue value,JSTaggedValue handler)193 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JSTaggedValue receiver,
194 JSTaggedValue holder,
195 JSTaggedValue value, JSTaggedValue handler)
196 {
197 INTERPRETER_TRACE(thread, StoreICWithHandler);
198 if (handler.IsInt()) {
199 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
200 if (HandlerBase::IsField(handlerInfo)) {
201 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
202 return JSTaggedValue::Undefined();
203 }
204 ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
205 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
206 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
207 }
208 if (handler.IsTransitionHandler()) {
209 StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
210 return JSTaggedValue::Undefined();
211 }
212 if (handler.IsTransWithProtoHandler()) {
213 return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
214 }
215 if (handler.IsPrototypeHandler()) {
216 return StorePrototype(thread, receiver, value, handler);
217 }
218 if (handler.IsPropertyBox()) {
219 return StoreGlobal(thread, value, handler);
220 }
221 if (handler.IsStoreTSHandler()) {
222 return StoreWithTS(thread, receiver, value, handler);
223 }
224 return JSTaggedValue::Undefined();
225 }
226
StorePrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)227 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
228 JSTaggedValue value, JSTaggedValue handler)
229 {
230 INTERPRETER_TRACE(thread, StorePrototype);
231 ASSERT(handler.IsPrototypeHandler());
232 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
233 auto cellValue = prototypeHandler->GetProtoCell();
234 if (cellValue.IsNull()) {
235 return JSTaggedValue::Hole();
236 }
237 ASSERT(cellValue.IsProtoChangeMarker());
238 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
239 if (cell->GetHasChanged()) {
240 return JSTaggedValue::Hole();
241 }
242 auto holder = prototypeHandler->GetHolder();
243 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
244 return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
245 }
246
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)247 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
248 JSTaggedValue value, JSTaggedValue handler)
249 {
250 INTERPRETER_TRACE(thread, StoreWithAOT);
251 ASSERT(handler.IsStoreTSHandler());
252 StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
253 auto cellValue = storeTSHandler->GetProtoCell();
254 ASSERT(cellValue.IsProtoChangeMarker());
255 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
256 if (cell->GetHasChanged()) {
257 return JSTaggedValue::Hole();
258 }
259 auto holder = storeTSHandler->GetHolder();
260 JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
261 auto handlerInfoInt = static_cast<uint32_t>(handlerInfo.GetInt());
262 if (HandlerBase::IsField(handlerInfoInt)) {
263 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
264 return JSTaggedValue::Undefined();
265 }
266 ASSERT(HandlerBase::IsAccessor(handlerInfoInt) || HandlerBase::IsInternalAccessor(handlerInfoInt));
267 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
268 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
269 }
270
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)271 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
272 JSTaggedValue handler, bool withPrototype)
273 {
274 INTERPRETER_TRACE(thread, StoreWithTransition);
275
276 JSHClass *newHClass = nullptr;
277 uint32_t handlerInfo = 0;
278
279 if (withPrototype) {
280 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
281 newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
282 handlerInfo = static_cast<uint32_t>(transWithProtoHandler->GetHandlerInfo().GetInt());
283 } else {
284 TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
285 newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
286 handlerInfo = static_cast<uint32_t>(transitionHandler->GetHandlerInfo().GetInt());
287 }
288
289 receiver->SynchronizedSetClass(newHClass);
290 ASSERT(HandlerBase::IsField(handlerInfo));
291
292 if (!HandlerBase::IsInlinedProps(handlerInfo)) {
293 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
294 int capacity = static_cast<int>(array->GetLength());
295 int index = HandlerBase::GetOffset(handlerInfo);
296 if (index >= capacity) {
297 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
298 [[maybe_unused]] EcmaHandleScope handleScope(thread);
299 JSHandle<TaggedArray> properties;
300 JSHandle<JSObject> objHandle(thread, receiver);
301 JSHandle<JSTaggedValue> valueHandle(thread, value);
302 if (capacity == 0) {
303 capacity = JSObject::MIN_PROPERTIES_LENGTH;
304 properties = factory->NewTaggedArray(capacity);
305 } else {
306 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
307 properties = factory->CopyArray(arrayHandle, capacity,
308 JSObject::ComputePropertyCapacity(capacity));
309 }
310 properties->Set(thread, index, valueHandle);
311 objHandle->SetProperties(thread, properties);
312 return;
313 }
314 array->Set(thread, index, value);
315 return;
316 }
317 StoreField(thread, receiver, value, handlerInfo);
318 }
319
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)320 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
321 JSTaggedValue handler)
322 {
323 INTERPRETER_TRACE(thread, StoreTransWithProto);
324 ASSERT(handler.IsTransWithProtoHandler());
325 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
326 auto cellValue = transWithProtoHandler->GetProtoCell();
327 ASSERT(cellValue.IsProtoChangeMarker());
328 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
329 if (cell->GetHasChanged()) {
330 return JSTaggedValue::Hole();
331 }
332
333 StoreWithTransition(thread, receiver, value, handler, true);
334 return JSTaggedValue::Undefined();
335 }
336
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint32_t handler)337 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint32_t handler)
338 {
339 INTERPRETER_TRACE(thread, StoreField);
340 int index = HandlerBase::GetOffset(handler);
341 if (HandlerBase::IsInlinedProps(handler)) {
342 SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
343 return;
344 }
345 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
346 ASSERT(index < static_cast<int>(array->GetLength()));
347 array->Set(thread, index, value);
348 }
349
LoadFromField(JSObject * receiver,uint32_t handlerInfo)350 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint32_t handlerInfo)
351 {
352 int index = HandlerBase::GetOffset(handlerInfo);
353 if (HandlerBase::IsInlinedProps(handlerInfo)) {
354 return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
355 }
356 return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
357 }
358
LoadGlobal(JSTaggedValue handler)359 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
360 {
361 ASSERT(handler.IsPropertyBox());
362 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
363 if (cell->IsInvalid()) {
364 return JSTaggedValue::Hole();
365 }
366 JSTaggedValue ret = cell->GetValue();
367 ASSERT(!ret.IsAccessorData());
368 return ret;
369 }
370
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)371 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
372 {
373 INTERPRETER_TRACE(thread, StoreGlobal);
374 ASSERT(handler.IsPropertyBox());
375 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
376 if (cell->IsInvalid()) {
377 return JSTaggedValue::Hole();
378 }
379 ASSERT(!cell->GetValue().IsAccessorData());
380 cell->SetValue(thread, value);
381 return JSTaggedValue::Undefined();
382 }
383
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)384 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
385 {
386 INTERPRETER_TRACE(thread, LoadPrototype);
387 ASSERT(handler.IsPrototypeHandler());
388 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
389 auto cellValue = prototypeHandler->GetProtoCell();
390 ASSERT(cellValue.IsProtoChangeMarker());
391 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
392 if (cell->GetHasChanged()) {
393 return JSTaggedValue::Hole();
394 }
395 auto holder = prototypeHandler->GetHolder();
396 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
397 return LoadICWithHandler(thread, receiver, holder, handlerInfo);
398 }
399
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)400 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
401 JSTaggedValue holder, JSTaggedValue handler)
402 {
403 INTERPRETER_TRACE(thread, LoadICWithHandler);
404 if (LIKELY(handler.IsInt())) {
405 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
406 if (LIKELY(HandlerBase::IsField(handlerInfo))) {
407 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
408 }
409 if (HandlerBase::IsNonExist(handlerInfo)) {
410 return JSTaggedValue::Undefined();
411 }
412 ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
413 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
414 return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
415 }
416
417 if (handler.IsPrototypeHandler()) {
418 return LoadPrototype(thread, receiver, handler);
419 }
420
421 return LoadGlobal(handler);
422 }
423
LoadElement(JSObject * receiver,JSTaggedValue key)424 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
425 {
426 auto index = TryToElementsIndex(key);
427 if (index < 0) {
428 return JSTaggedValue::Hole();
429 }
430 uint32_t elementIndex = static_cast<uint32_t>(index);
431 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
432 if (elements->GetLength() <= elementIndex) {
433 return JSTaggedValue::Hole();
434 }
435
436 JSTaggedValue value = elements->Get(elementIndex);
437 // TaggedArray elements
438 return value;
439 }
440
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)441 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
442 JSTaggedValue value, JSTaggedValue handler)
443 {
444 INTERPRETER_TRACE(thread, StoreElement);
445 auto index = TryToElementsIndex(key);
446 if (index < 0) {
447 return JSTaggedValue::Hole();
448 }
449 uint32_t elementIndex = static_cast<uint32_t>(index);
450 if (handler.IsInt()) {
451 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
452 [[maybe_unused]] EcmaHandleScope handleScope(thread);
453 JSHandle<JSObject> receiverHandle(thread, receiver);
454 if (HandlerBase::IsJSArray(handlerInfo)) {
455 JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
456 if (receiveValue.IsJSCOWArray()) {
457 // Copy on write array.
458 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
459 }
460 JSArray *arr = JSArray::Cast(*receiverHandle);
461 uint32_t oldLength = arr->GetArrayLength();
462 if (elementIndex >= oldLength) {
463 arr->SetArrayLength(thread, elementIndex + 1);
464 }
465 }
466 TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
467 uint32_t capacity = elements->GetLength();
468 if (elementIndex >= capacity) {
469 if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
470 return JSTaggedValue::Hole();
471 }
472 JSHandle<JSTaggedValue> valueHandle(thread, value);
473 elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
474 receiverHandle->SetElements(thread, JSTaggedValue(elements));
475 elements->Set(thread, elementIndex, valueHandle);
476 return JSTaggedValue::Undefined();
477 }
478 elements->Set(thread, elementIndex, value);
479 } else {
480 ASSERT(handler.IsPrototypeHandler());
481 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
482 auto cellValue = prototypeHandler->GetProtoCell();
483 ASSERT(cellValue.IsProtoChangeMarker());
484 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
485 if (cell->GetHasChanged()) {
486 return JSTaggedValue::Hole();
487 }
488 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
489 return StoreElement(thread, receiver, key, value, handlerInfo);
490 }
491 return JSTaggedValue::Undefined();
492 }
493
TryToElementsIndex(JSTaggedValue key)494 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
495 {
496 if (LIKELY(key.IsInt())) {
497 return key.GetInt();
498 }
499
500 if (key.IsString()) {
501 uint32_t index = 0;
502 if (JSTaggedValue::StringToElementIndex(key, &index)) {
503 return static_cast<int64_t>(index);
504 }
505 }
506
507 if (key.IsDouble()) {
508 double number = key.GetDouble();
509 auto integer = static_cast<int32_t>(number);
510 if (number == integer) {
511 return integer;
512 }
513 }
514
515 return -1;
516 }
517
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)518 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
519 JSTaggedValue key, uint32_t slotId, ICKind kind)
520 {
521 [[maybe_unused]] EcmaHandleScope handleScope(thread);
522 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
523 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
524 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
525 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
526 return icRuntime.LoadMiss(receiverHandle, keyHandle);
527 }
528
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind)529 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
530 JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind)
531 {
532 [[maybe_unused]] EcmaHandleScope handleScope(thread);
533 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
534 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
535 auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
536 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
537 StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
538 return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle);
539 }
540 } // namespace panda::ecmascript
541
542 #endif // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
543