1 /*
2 * Copyright (c) 2021 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 != JSTaggedValue::Undefined() && 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 ASSERT(cellValue.IsProtoChangeMarker());
235 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
236 if (cell->GetHasChanged()) {
237 return JSTaggedValue::Hole();
238 }
239 auto holder = prototypeHandler->GetHolder();
240 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
241 return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
242 }
243
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)244 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
245 JSTaggedValue value, JSTaggedValue handler)
246 {
247 INTERPRETER_TRACE(thread, StoreWithAOT);
248 ASSERT(handler.IsStoreTSHandler());
249 StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
250 auto cellValue = storeTSHandler->GetProtoCell();
251 ASSERT(cellValue.IsProtoChangeMarker());
252 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
253 if (cell->GetHasChanged()) {
254 return JSTaggedValue::Hole();
255 }
256 auto holder = storeTSHandler->GetHolder();
257 JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
258 auto handlerInfoInt = static_cast<uint32_t>(handlerInfo.GetInt());
259 if (HandlerBase::IsField(handlerInfoInt)) {
260 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
261 return JSTaggedValue::Undefined();
262 }
263 ASSERT(HandlerBase::IsAccessor(handlerInfoInt) || HandlerBase::IsInternalAccessor(handlerInfoInt));
264 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
265 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
266 }
267
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)268 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
269 JSTaggedValue handler, bool withPrototype)
270 {
271 INTERPRETER_TRACE(thread, StoreWithTransition);
272
273 JSHClass *newHClass = nullptr;
274 uint32_t handlerInfo = 0;
275
276 if (withPrototype) {
277 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
278 newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
279 handlerInfo = static_cast<uint32_t>(transWithProtoHandler->GetHandlerInfo().GetInt());
280 } else {
281 TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
282 newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
283 handlerInfo = static_cast<uint32_t>(transitionHandler->GetHandlerInfo().GetInt());
284 }
285
286 receiver->SetClass(newHClass);
287 ASSERT(HandlerBase::IsField(handlerInfo));
288
289 if (!HandlerBase::IsInlinedProps(handlerInfo)) {
290 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
291 int capacity = static_cast<int>(array->GetLength());
292 int index = HandlerBase::GetOffset(handlerInfo);
293 if (index >= capacity) {
294 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
295 [[maybe_unused]] EcmaHandleScope handleScope(thread);
296 JSHandle<TaggedArray> properties;
297 JSHandle<JSObject> objHandle(thread, receiver);
298 JSHandle<JSTaggedValue> valueHandle(thread, value);
299 if (capacity == 0) {
300 capacity = JSObject::MIN_PROPERTIES_LENGTH;
301 properties = factory->NewTaggedArray(capacity);
302 } else {
303 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
304 properties = factory->CopyArray(arrayHandle, capacity,
305 JSObject::ComputePropertyCapacity(capacity));
306 }
307 properties->Set(thread, index, valueHandle);
308 objHandle->SetProperties(thread, properties);
309 return;
310 }
311 array->Set(thread, index, value);
312 return;
313 }
314 StoreField(thread, receiver, value, handlerInfo);
315 }
316
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)317 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
318 JSTaggedValue handler)
319 {
320 INTERPRETER_TRACE(thread, StoreTransWithProto);
321 ASSERT(handler.IsTransWithProtoHandler());
322 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
323 auto cellValue = transWithProtoHandler->GetProtoCell();
324 ASSERT(cellValue.IsProtoChangeMarker());
325 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
326 if (cell->GetHasChanged()) {
327 return JSTaggedValue::Hole();
328 }
329
330 StoreWithTransition(thread, receiver, value, handler, true);
331 return JSTaggedValue::Undefined();
332 }
333
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint32_t handler)334 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint32_t handler)
335 {
336 INTERPRETER_TRACE(thread, StoreField);
337 int index = HandlerBase::GetOffset(handler);
338 if (HandlerBase::IsInlinedProps(handler)) {
339 SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
340 return;
341 }
342 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
343 ASSERT(index < static_cast<int>(array->GetLength()));
344 array->Set(thread, index, value);
345 }
346
LoadFromField(JSObject * receiver,uint32_t handlerInfo)347 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint32_t handlerInfo)
348 {
349 int index = HandlerBase::GetOffset(handlerInfo);
350 if (HandlerBase::IsInlinedProps(handlerInfo)) {
351 return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
352 }
353 return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
354 }
355
LoadGlobal(JSTaggedValue handler)356 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
357 {
358 ASSERT(handler.IsPropertyBox());
359 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
360 if (cell->IsInvalid()) {
361 return JSTaggedValue::Hole();
362 }
363 JSTaggedValue ret = cell->GetValue();
364 ASSERT(!ret.IsAccessorData());
365 return ret;
366 }
367
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)368 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
369 {
370 INTERPRETER_TRACE(thread, StoreGlobal);
371 ASSERT(handler.IsPropertyBox());
372 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
373 if (cell->IsInvalid()) {
374 return JSTaggedValue::Hole();
375 }
376 ASSERT(!cell->GetValue().IsAccessorData());
377 cell->SetValue(thread, value);
378 return JSTaggedValue::Undefined();
379 }
380
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)381 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
382 {
383 INTERPRETER_TRACE(thread, LoadPrototype);
384 ASSERT(handler.IsPrototypeHandler());
385 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
386 auto cellValue = prototypeHandler->GetProtoCell();
387 ASSERT(cellValue.IsProtoChangeMarker());
388 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
389 if (cell->GetHasChanged()) {
390 return JSTaggedValue::Hole();
391 }
392 auto holder = prototypeHandler->GetHolder();
393 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
394 return LoadICWithHandler(thread, receiver, holder, handlerInfo);
395 }
396
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)397 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
398 JSTaggedValue holder, JSTaggedValue handler)
399 {
400 INTERPRETER_TRACE(thread, LoadICWithHandler);
401 if (LIKELY(handler.IsInt())) {
402 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
403 if (LIKELY(HandlerBase::IsField(handlerInfo))) {
404 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
405 }
406 if (HandlerBase::IsNonExist(handlerInfo)) {
407 return JSTaggedValue::Undefined();
408 }
409 ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
410 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
411 return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
412 }
413
414 if (handler.IsPrototypeHandler()) {
415 return LoadPrototype(thread, receiver, handler);
416 }
417
418 return LoadGlobal(handler);
419 }
420
LoadElement(JSObject * receiver,JSTaggedValue key)421 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
422 {
423 auto index = TryToElementsIndex(key);
424 if (index < 0) {
425 return JSTaggedValue::Hole();
426 }
427 uint32_t elementIndex = static_cast<uint32_t>(index);
428 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
429 if (elements->GetLength() <= elementIndex) {
430 return JSTaggedValue::Hole();
431 }
432
433 JSTaggedValue value = elements->Get(elementIndex);
434 // TaggedArray elements
435 return value;
436 }
437
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)438 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
439 JSTaggedValue value, JSTaggedValue handler)
440 {
441 INTERPRETER_TRACE(thread, StoreElement);
442 auto index = TryToElementsIndex(key);
443 if (index < 0) {
444 return JSTaggedValue::Hole();
445 }
446 uint32_t elementIndex = static_cast<uint32_t>(index);
447 if (handler.IsInt()) {
448 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
449 [[maybe_unused]] EcmaHandleScope handleScope(thread);
450 JSHandle<JSObject> receiverHandle(thread, receiver);
451 if (HandlerBase::IsJSArray(handlerInfo)) {
452 JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
453 if (receiveValue.IsJSCOWArray()) {
454 // Copy on write array.
455 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
456 }
457 JSArray *arr = JSArray::Cast(*receiverHandle);
458 uint32_t oldLength = arr->GetArrayLength();
459 if (elementIndex >= oldLength) {
460 arr->SetArrayLength(thread, elementIndex + 1);
461 }
462 }
463 TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
464 uint32_t capacity = elements->GetLength();
465 if (elementIndex >= capacity) {
466 if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
467 return JSTaggedValue::Hole();
468 }
469 JSHandle<JSTaggedValue> valueHandle(thread, value);
470 elements = *JSObject::GrowElementsCapacity(thread, receiverHandle,
471 JSObject::ComputeElementCapacity(elementIndex + 1));
472 receiverHandle->SetElements(thread, JSTaggedValue(elements));
473 elements->Set(thread, elementIndex, valueHandle);
474 return JSTaggedValue::Undefined();
475 }
476 elements->Set(thread, elementIndex, value);
477 } else {
478 ASSERT(handler.IsPrototypeHandler());
479 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
480 auto cellValue = prototypeHandler->GetProtoCell();
481 ASSERT(cellValue.IsProtoChangeMarker());
482 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
483 if (cell->GetHasChanged()) {
484 return JSTaggedValue::Hole();
485 }
486 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
487 return StoreElement(thread, receiver, key, value, handlerInfo);
488 }
489 return JSTaggedValue::Undefined();
490 }
491
TryToElementsIndex(JSTaggedValue key)492 ARK_INLINE int32_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
493 {
494 if (LIKELY(key.IsInt())) {
495 return key.GetInt();
496 }
497
498 if (key.IsString()) {
499 uint32_t index = 0;
500 if (JSTaggedValue::StringToElementIndex(key, &index)) {
501 return static_cast<int32_t>(index);
502 }
503 }
504
505 if (key.IsDouble()) {
506 double number = key.GetDouble();
507 auto integer = static_cast<int32_t>(number);
508 if (number == integer) {
509 return integer;
510 }
511 }
512
513 return -1;
514 }
515
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)516 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
517 JSTaggedValue key, uint32_t slotId, ICKind kind)
518 {
519 [[maybe_unused]] EcmaHandleScope handleScope(thread);
520 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
521 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
522 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
523 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
524 return icRuntime.LoadMiss(receiverHandle, keyHandle);
525 }
526
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind)527 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
528 JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind)
529 {
530 [[maybe_unused]] EcmaHandleScope handleScope(thread);
531 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
532 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
533 auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
534 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
535 StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
536 return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle);
537 }
538 } // namespace panda::ecmascript
539
540 #endif // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H_
541