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