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(thread, 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 HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
227 if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
228 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
229 return JSTaggedValue::Undefined();
230 }
231 bool isShared = HandlerBase::IsStoreShared(handlerInfo);
232 if (isShared) {
233 SharedFieldType fieldType { HandlerBase::GetFieldType(handlerInfo) };
234 bool hasAccessor = HandlerBase::IsAccessor(handlerInfo);
235 if (!hasAccessor) {
236 if (!ClassHelper::MatchFieldType(fieldType, value)) {
237 [[maybe_unused]] EcmaHandleScope handleScope(thread);
238 THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty),
239 JSTaggedValue::Exception());
240 }
241 if (value.IsTreeString()) {
242 [[maybe_unused]] EcmaHandleScope handleScope(thread);
243 JSHandle<JSTaggedValue> objHandle(thread, receiver);
244 JSHandle<JSTaggedValue> holderHandle(thread, holder);
245 JSHandle<JSTaggedValue> valueHandle(thread, value);
246 value = JSTaggedValue::PublishSharedValue(thread, valueHandle).GetTaggedValue();
247 receiver = objHandle.GetTaggedValue();
248 holder = holderHandle.GetTaggedValue();
249 }
250 }
251 HandlerBase::ClearSharedStoreKind(handlerInfo);
252 return StoreICWithHandler(thread, receiver, holder, value,
253 JSTaggedValue::WrapUint64(handlerInfo));
254 }
255 ASSERT(HandlerBase::IsAccessor(handlerInfo));
256 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
257 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
258 }
259 if (handler.IsTransitionHandler()) {
260 StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
261 return JSTaggedValue::Undefined();
262 }
263 if (handler.IsTransWithProtoHandler()) {
264 return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
265 }
266 if (handler.IsPrototypeHandler()) {
267 return StorePrototype(thread, receiver, value, handler);
268 }
269 if (handler.IsPropertyBox()) {
270 return StoreGlobal(thread, value, handler);
271 }
272 if (handler.IsStoreAOTHandler()) {
273 return StoreWithTS(thread, receiver, value, handler);
274 }
275 return JSTaggedValue::Undefined();
276 }
277
StorePrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)278 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
279 JSTaggedValue value, JSTaggedValue handler)
280 {
281 INTERPRETER_TRACE(thread, StorePrototype);
282 ASSERT(handler.IsPrototypeHandler());
283 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
284 if (!receiver.IsJSShared()) {
285 auto cellValue = prototypeHandler->GetProtoCell();
286 if (cellValue.IsNull()) {
287 return JSTaggedValue::Hole();
288 }
289 ASSERT(cellValue.IsProtoChangeMarker());
290 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
291 if (cell->GetHasChanged()) {
292 return JSTaggedValue::Hole();
293 }
294 }
295 auto holder = prototypeHandler->GetHolder();
296 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
297 return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
298 }
299
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)300 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
301 JSTaggedValue value, JSTaggedValue handler)
302 {
303 INTERPRETER_TRACE(thread, StoreWithAOT);
304 ASSERT(handler.IsStoreAOTHandler());
305 StoreAOTHandler *storeAOTHandler = StoreAOTHandler::Cast(handler.GetTaggedObject());
306 auto cellValue = storeAOTHandler->GetProtoCell();
307 if (cellValue == JSTaggedValue::Undefined()) {
308 return JSTaggedValue::Hole();
309 }
310 ASSERT(cellValue.IsProtoChangeMarker());
311 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
312 if (cell->GetHasChanged()) {
313 return JSTaggedValue::Hole();
314 }
315 auto holder = storeAOTHandler->GetHolder();
316 JSTaggedValue handlerInfo = storeAOTHandler->GetHandlerInfo();
317 auto handlerInfoInt = JSTaggedValue::UnwrapToUint64(handlerInfo);
318 if (HandlerBase::IsField(handlerInfoInt)) {
319 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
320 return JSTaggedValue::Undefined();
321 }
322 ASSERT(HandlerBase::IsAccessor(handlerInfoInt));
323 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
324 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
325 }
326
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)327 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
328 JSTaggedValue handler, bool withPrototype)
329 {
330 INTERPRETER_TRACE(thread, StoreWithTransition);
331
332 JSHClass *newHClass = nullptr;
333 uint64_t handlerInfo = 0;
334
335 if (withPrototype) {
336 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
337 newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
338 handlerInfo = JSTaggedValue::UnwrapToUint64(transWithProtoHandler->GetHandlerInfo());
339 } else {
340 TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
341 newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
342 handlerInfo = JSTaggedValue::UnwrapToUint64(transitionHandler->GetHandlerInfo());
343 }
344 JSHandle<JSHClass> newHClassHandle(thread, newHClass);
345 JSHandle<JSHClass> oldHClassHandle(thread, receiver->GetJSHClass());
346 if (newHClassHandle->IsPrototype()) {
347 newHClassHandle->SetProtoChangeDetails(thread, oldHClassHandle->GetProtoChangeDetails());
348 }
349 JSHandle<JSObject> objHandle(thread, receiver);
350 ElementsKind oldKind = receiver->GetJSHClass()->GetElementsKind();
351 JSHClass::RestoreElementsKindToGeneric(newHClass);
352 objHandle->SynchronizedSetClass(thread, newHClass);
353 JSObject::TryMigrateToGenericKindForJSObject(thread, objHandle, oldKind);
354
355 ASSERT(HandlerBase::IsField(handlerInfo));
356
357 if (!HandlerBase::IsInlinedProps(handlerInfo)) {
358 TaggedArray *array = TaggedArray::Cast(objHandle->GetProperties().GetTaggedObject());
359 int capacity = static_cast<int>(array->GetLength());
360 int index = HandlerBase::GetOffset(handlerInfo);
361 if (index >= capacity) {
362 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
363 [[maybe_unused]] EcmaHandleScope handleScope(thread);
364 JSHandle<TaggedArray> properties;
365 JSHandle<JSTaggedValue> valueHandle(thread, value);
366 if (capacity == 0) {
367 capacity = JSObject::MIN_PROPERTIES_LENGTH;
368 properties = factory->NewTaggedArray(capacity);
369 } else {
370 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
371 uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity();
372 uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity,
373 maxNonInlinedFastPropsCapacity);
374 properties = factory->CopyArray(arrayHandle, capacity, newLen);
375 }
376 properties->Set(thread, index, valueHandle);
377 objHandle->SetProperties(thread, properties);
378 return;
379 }
380 array->Set(thread, index, value);
381 return;
382 }
383 StoreField(thread, *objHandle, value, handlerInfo);
384 }
385
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)386 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
387 JSTaggedValue handler)
388 {
389 INTERPRETER_TRACE(thread, StoreTransWithProto);
390 ASSERT(handler.IsTransWithProtoHandler());
391 ASSERT(!receiver->GetClass()->IsJSShared());
392 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
393 auto cellValue = transWithProtoHandler->GetProtoCell();
394 if (cellValue == JSTaggedValue::Undefined()) {
395 return JSTaggedValue::Hole();
396 }
397 ASSERT(cellValue.IsProtoChangeMarker());
398 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
399 if (cell->GetHasChanged()) {
400 return JSTaggedValue::Hole();
401 }
402
403 StoreWithTransition(thread, receiver, value, handler, true);
404 return JSTaggedValue::Undefined();
405 }
406
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint64_t handler)407 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint64_t handler)
408 {
409 INTERPRETER_TRACE(thread, StoreField);
410 int index = HandlerBase::GetOffset(handler);
411 if (HandlerBase::IsInlinedProps(handler)) {
412 SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
413 return;
414 }
415 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
416 ASSERT(index < static_cast<int>(array->GetLength()));
417 array->Set(thread, index, value);
418 }
419
LoadFromField(JSObject * receiver,uint64_t handlerInfo)420 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint64_t handlerInfo)
421 {
422 int index = HandlerBase::GetOffset(handlerInfo);
423 if (HandlerBase::IsInlinedProps(handlerInfo)) {
424 return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
425 }
426 return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
427 }
428
LoadGlobal(JSTaggedValue handler)429 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
430 {
431 ASSERT(handler.IsPropertyBox());
432 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
433 if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
434 return JSTaggedValue::Hole();
435 }
436 JSTaggedValue ret = cell->GetValue();
437 ASSERT(!ret.IsAccessorData());
438 return ret;
439 }
440
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)441 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
442 {
443 INTERPRETER_TRACE(thread, StoreGlobal);
444 ASSERT(handler.IsPropertyBox());
445 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
446 if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
447 return JSTaggedValue::Hole();
448 }
449 ASSERT(!cell->GetValue().IsAccessorData());
450 cell->SetValue(thread, value);
451 return JSTaggedValue::Undefined();
452 }
453
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)454 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
455 {
456 INTERPRETER_TRACE(thread, LoadPrototype);
457 ASSERT(handler.IsPrototypeHandler());
458 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
459 auto holder = prototypeHandler->GetHolder();
460 if (!receiver.IsJSShared()) {
461 auto cellValue = prototypeHandler->GetProtoCell();
462 if (cellValue == JSTaggedValue::Undefined()) {
463 return JSTaggedValue::Hole();
464 }
465 ASSERT(cellValue.IsProtoChangeMarker());
466 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
467 if (cell->GetHasChanged()) {
468 return JSTaggedValue::Hole();
469 }
470
471 // For "Not Found" case (holder equals Undefined()),
472 // we should ensure that both GetNotFoundHasChanged() and GetHasChanged() return false.
473 if (holder == JSTaggedValue::Undefined()) {
474 if (cell->GetNotFoundHasChanged()) {
475 return JSTaggedValue::Hole();
476 }
477 return JSTaggedValue::Undefined();
478 }
479 }
480
481 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
482 return LoadICWithHandler(thread, receiver, holder, handlerInfo);
483 }
484
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)485 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
486 JSTaggedValue holder, JSTaggedValue handler)
487 {
488 INTERPRETER_TRACE(thread, LoadICWithHandler);
489 if (LIKELY(handler.IsInt())) {
490 auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
491 HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
492 if (LIKELY(HandlerBase::IsField(handlerInfo))) {
493 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
494 }
495 if (HandlerBase::IsString(handlerInfo) || HandlerBase::IsNumber(handlerInfo)) {
496 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
497 }
498
499 // For the special "Not Found" case we may generate ic by "LoadHandler::LoadProperty".
500 // In this situation, you can trust ic without ChangeMarker.
501 if (HandlerBase::IsNonExist(handlerInfo)) {
502 return JSTaggedValue::Undefined();
503 }
504
505 if (HandlerBase::IsStringLength(handlerInfo)) {
506 return JSTaggedNumber((EcmaStringAccessor(EcmaString::Cast(holder)).GetLength()));
507 }
508 ASSERT(HandlerBase::IsAccessor(handlerInfo));
509 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
510 return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
511 }
512
513 if (handler.IsPrototypeHandler()) {
514 return LoadPrototype(thread, receiver, handler);
515 }
516
517 return LoadGlobal(handler);
518 }
519
LoadICWithElementHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler,JSTaggedValue key)520 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *thread, JSTaggedValue receiver,
521 JSTaggedValue handler, JSTaggedValue key)
522 {
523 if (LIKELY(handler.IsInt())) {
524 auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
525 HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
526 if (HandlerBase::IsNormalElement(handlerInfo)) {
527 return LoadElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key);
528 } else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
529 return LoadTypedArrayElement(thread, receiver, key);
530 }
531 ASSERT(HandlerBase::IsStringElement(handlerInfo));
532 return LoadStringElement(thread, receiver, key);
533 }
534 return JSTaggedValue::Hole();
535 }
536
LoadElement(JSThread * thread,JSObject * receiver,JSTaggedValue key)537 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSThread *thread, JSObject *receiver, JSTaggedValue key)
538 {
539 auto index = TryToElementsIndex(key);
540 if (index < 0) {
541 return JSTaggedValue::Hole();
542 }
543 uint32_t elementIndex = static_cast<uint32_t>(index);
544 if (ElementAccessor::GetElementsLength(receiver) <= elementIndex) {
545 return JSTaggedValue::Hole();
546 }
547
548 JSTaggedValue value = ElementAccessor::Get(thread, receiver, elementIndex);
549 // TaggedArray elements
550 return value;
551 }
552
LoadStringElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)553 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
554 {
555 auto index = TryToElementsIndex(key);
556 if (index < 0) {
557 return JSTaggedValue::Hole();
558 }
559 uint32_t elementIndex = static_cast<uint32_t>(index);
560 uint16_t tmpChar = 0;
561 {
562 JSHandle<EcmaString> strHandle(thread, receiver);
563 JSHandle<EcmaString> strFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), strHandle));
564 if (EcmaStringAccessor(strFlat).GetLength() <= elementIndex) {
565 return JSTaggedValue::Hole();
566 }
567 tmpChar = EcmaStringAccessor(strFlat).Get(elementIndex);
568 }
569 auto factory = thread->GetEcmaVM()->GetFactory();
570 JSHandle<JSTaggedValue> value(factory->NewFromUtf16(&tmpChar, 1));
571 return value.GetTaggedValue();
572 }
573
LoadTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)574 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
575 JSTaggedValue key)
576 {
577 auto index = TryToElementsIndex(key);
578 if (index < 0) {
579 return JSTaggedValue::Hole();
580 }
581 auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
582 uint32_t arrLen = typedarrayObj->GetArrayLength();
583 if (index >= arrLen) {
584 return JSTaggedValue::Hole();
585 }
586 JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
587 return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, type);
588 }
589
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)590 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
591 JSTaggedValue value, JSTaggedValue handler)
592 {
593 INTERPRETER_TRACE(thread, StoreElement);
594 auto index = TryToElementsIndex(key);
595 if (index < 0) {
596 return JSTaggedValue::Hole();
597 }
598 uint32_t elementIndex = static_cast<uint32_t>(index);
599 if (handler.IsInt()) {
600 auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
601 HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
602 [[maybe_unused]] EcmaHandleScope handleScope(thread);
603 JSHandle<JSObject> receiverHandle(thread, receiver);
604 JSHandle<JSTaggedValue> valueHandle(thread, value);
605 if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
606 return StoreTypedArrayElement(thread, JSTaggedValue::Cast(receiver), key, value);
607 } else if (HandlerBase::IsJSArray(handlerInfo)) {
608 JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
609 if (receiveValue.IsJSCOWArray()) {
610 // Copy on write array.
611 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
612 }
613 JSArray *arr = JSArray::Cast(*receiverHandle);
614 uint32_t oldLength = arr->GetArrayLength();
615 if (elementIndex >= oldLength) {
616 arr->SetArrayLength(thread, elementIndex + 1);
617 }
618 }
619 TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
620 uint32_t capacity = elements->GetLength();
621 if (elementIndex >= capacity) {
622 if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
623 return JSTaggedValue::Hole();
624 }
625 elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
626 receiverHandle->SetElements(thread, JSTaggedValue(elements));
627 elements->Set(thread, elementIndex, valueHandle);
628 return JSTaggedValue::Undefined();
629 }
630 elements->Set(thread, elementIndex, valueHandle);
631 } else {
632 ASSERT(handler.IsPrototypeHandler());
633 if (receiver->GetClass()->IsJSShared()) {
634 THROW_TYPE_ERROR_AND_RETURN(thread,
635 GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception());
636 }
637 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
638 auto cellValue = prototypeHandler->GetProtoCell();
639 if (cellValue == JSTaggedValue::Undefined()) {
640 return JSTaggedValue::Hole();
641 }
642 ASSERT(cellValue.IsProtoChangeMarker());
643 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
644 if (cell->GetHasChanged()) {
645 return JSTaggedValue::Hole();
646 }
647 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
648 return StoreElement(thread, receiver, key, value, handlerInfo);
649 }
650 return JSTaggedValue::Undefined();
651 }
652
StoreTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)653 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
654 JSTaggedValue key, JSTaggedValue value)
655 {
656 auto index = TryToElementsIndex(key);
657 if (index < 0) {
658 return JSTaggedValue::Hole();
659 }
660 auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
661 uint32_t arrLen = typedarrayObj->GetArrayLength();
662 if (index >= arrLen) {
663 return JSTaggedValue::Hole();
664 }
665 JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
666 return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, type);
667 }
668
TryToElementsIndex(JSTaggedValue key)669 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
670 {
671 if (LIKELY(key.IsInt())) {
672 return key.GetInt();
673 }
674
675 if (key.IsString()) {
676 uint32_t index = 0;
677 if (JSTaggedValue::StringToElementIndex(key, &index)) {
678 return static_cast<int64_t>(index);
679 }
680 }
681
682 if (key.IsDouble()) {
683 double number = key.GetDouble();
684 auto integer = static_cast<int32_t>(number);
685 if (number == integer) {
686 return integer;
687 }
688 }
689
690 return -1;
691 }
692
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)693 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
694 JSTaggedValue key, uint32_t slotId, ICKind kind)
695 {
696 [[maybe_unused]] EcmaHandleScope handleScope(thread);
697 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
698 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
699 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
700 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
701 return icRuntime.LoadMiss(receiverHandle, keyHandle);
702 }
703
LoadValueMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)704 JSTaggedValue ICRuntimeStub::LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
705 JSTaggedValue key, uint32_t slotId, ICKind kind)
706 {
707 [[maybe_unused]] EcmaHandleScope handleScope(thread);
708 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
709 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
710 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
711 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
712 return icRuntime.LoadValueMiss(receiverHandle, keyHandle);
713 }
714
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind,bool isOwn)715 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
716 JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)
717 {
718 [[maybe_unused]] EcmaHandleScope handleScope(thread);
719 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
720 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
721 auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
722 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
723 StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
724 return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle, isOwn);
725 }
726 } // namespace panda::ecmascript
727
728 #endif // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
729