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