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 auto hclass = thread->GetEcmaVM()->GetGlobalEnv()->GetNumberFunction()->GetTaggedObject()->GetClass();
101 if (firstValue.GetWeakReferentUnChecked() == hclass) {
102 return LoadICWithHandler(thread, receiver, receiver, secondValue);
103 }
104 }
105 return JSTaggedValue::Hole();
106 }
107
LoadICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)108 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
109 JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
110 {
111 INTERPRETER_TRACE(thread, LoadICByName);
112 return LoadMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::NamedLoadIC);
113 }
114
TryLoadICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue)115 ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
116 JSTaggedValue firstValue, JSTaggedValue secondValue)
117 {
118 INTERPRETER_TRACE(thread, TryLoadICByValue);
119 if (receiver.IsHeapObject()) {
120 auto hclass = receiver.GetTaggedObject()->GetClass();
121 if (firstValue.GetWeakReferentUnChecked() == hclass) {
122 if (HandlerBase::IsNormalElement(secondValue.GetInt())) {
123 return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
124 } else if (HandlerBase::IsTypedArrayElement(secondValue.GetInt())) {
125 return LoadTypedArrayElement(thread, receiver, key);
126 }
127 ASSERT(HandlerBase::IsStringElement(secondValue.GetInt()));
128 return LoadStringElement(thread, receiver, key);
129 }
130 // check ploy
131 if (secondValue.IsHole() && !firstValue.IsHole()) {
132 JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
133 return LoadICWithElementHandler(thread, receiver, cachedHandler, key);
134 }
135 // Check key
136 if (firstValue == key) {
137 JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
138 if (!cachedHandler.IsHole()) {
139 return LoadICWithHandler(thread, receiver, receiver, cachedHandler);
140 }
141 }
142 }
143 return JSTaggedValue::Hole();
144 }
145
LoadICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId)146 ARK_NOINLINE JSTaggedValue ICRuntimeStub::LoadICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
147 JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId)
148 {
149 INTERPRETER_TRACE(thread, LoadICByValue);
150 return LoadValueMiss(thread, profileTypeInfo, receiver, key, slotId, ICKind::LoadIC);
151 }
152
TryStoreICByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)153 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByValue(JSThread *thread, JSTaggedValue receiver,
154 JSTaggedValue key, JSTaggedValue firstValue,
155 JSTaggedValue secondValue, JSTaggedValue value)
156 {
157 INTERPRETER_TRACE(thread, TryStoreICByValue);
158 if (receiver.IsHeapObject()) {
159 auto hclass = receiver.GetTaggedObject()->GetClass();
160 if (firstValue.GetWeakReferentUnChecked() == hclass) {
161 return StoreElement(thread, JSObject::Cast(receiver.GetTaggedObject()), key, value, secondValue);
162 }
163 // Check key
164 if (firstValue == key) {
165 JSTaggedValue cachedHandler = CheckPolyHClass(secondValue, hclass);
166 if (!cachedHandler.IsHole()) {
167 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
168 }
169 }
170 }
171
172 return JSTaggedValue::Hole();
173 }
174
StoreICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)175 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
176 JSTaggedValue receiver, JSTaggedValue key,
177 JSTaggedValue value, uint32_t slotId)
178 {
179 INTERPRETER_TRACE(thread, StoreICByValue);
180 return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC);
181 }
182
StoreOwnICByValue(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)183 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreOwnICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
184 JSTaggedValue receiver, JSTaggedValue key,
185 JSTaggedValue value, uint32_t slotId)
186 {
187 INTERPRETER_TRACE(thread, StoreOwnICByValue);
188 return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC, true);
189 }
190
TryStoreICByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue value)191 ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByName(JSThread *thread, JSTaggedValue receiver,
192 JSTaggedValue firstValue, JSTaggedValue secondValue,
193 JSTaggedValue value)
194 {
195 INTERPRETER_TRACE(thread, TryStoreICByName);
196 if (receiver.IsHeapObject()) {
197 auto hclass = receiver.GetTaggedObject()->GetClass();
198 if (firstValue.GetWeakReferentUnChecked() == hclass) {
199 return StoreICWithHandler(thread, receiver, receiver, value, secondValue);
200 }
201 JSTaggedValue cachedHandler = CheckPolyHClass(firstValue, hclass);
202 if (!cachedHandler.IsHole()) {
203 return StoreICWithHandler(thread, receiver, receiver, value, cachedHandler);
204 }
205 }
206 return JSTaggedValue::Hole();
207 }
208
StoreICByName(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId)209 ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
210 JSTaggedValue receiver, JSTaggedValue key,
211 JSTaggedValue value, uint32_t slotId)
212 {
213 INTERPRETER_TRACE(thread, StoreICByName);
214 return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::NamedStoreIC);
215 }
216
StoreICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue value,JSTaggedValue handler)217 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JSTaggedValue receiver,
218 JSTaggedValue holder,
219 JSTaggedValue value, JSTaggedValue handler)
220 {
221 INTERPRETER_TRACE(thread, StoreICWithHandler);
222 if (handler.IsInt()) {
223 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
224 if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
225 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
226 return JSTaggedValue::Undefined();
227 }
228 bool isShared = HandlerBase::IsStoreShared(handlerInfo);
229 if (isShared) {
230 TrackType trackType { HandlerBase::GetTrackType(handlerInfo) };
231 if (!ClassHelper::MatchTrackType(trackType, value)) {
232 THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty),
233 JSTaggedValue::Exception());
234 }
235 HandlerBase::ClearSharedStoreKind(handlerInfo);
236 return StoreICWithHandler(thread, receiver, holder, value,
237 JSTaggedValue(static_cast<int32_t>(handlerInfo)));
238 }
239 ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
240 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
241 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
242 }
243 if (handler.IsTransitionHandler()) {
244 StoreWithTransition(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
245 return JSTaggedValue::Undefined();
246 }
247 if (handler.IsTransWithProtoHandler()) {
248 return StoreTransWithProto(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handler);
249 }
250 if (handler.IsPrototypeHandler()) {
251 return StorePrototype(thread, receiver, value, handler);
252 }
253 if (handler.IsPropertyBox()) {
254 return StoreGlobal(thread, value, handler);
255 }
256 if (handler.IsStoreTSHandler()) {
257 return StoreWithTS(thread, receiver, value, handler);
258 }
259 return JSTaggedValue::Undefined();
260 }
261
StorePrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)262 JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue receiver,
263 JSTaggedValue value, JSTaggedValue handler)
264 {
265 INTERPRETER_TRACE(thread, StorePrototype);
266 ASSERT(handler.IsPrototypeHandler());
267 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
268 auto cellValue = prototypeHandler->GetProtoCell();
269 if (cellValue.IsNull()) {
270 return JSTaggedValue::Hole();
271 }
272 ASSERT(cellValue.IsProtoChangeMarker());
273 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
274 if (cell->GetHasChanged()) {
275 return JSTaggedValue::Hole();
276 }
277 auto holder = prototypeHandler->GetHolder();
278 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
279 return StoreICWithHandler(thread, receiver, holder, value, handlerInfo);
280 }
281
StoreWithTS(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue handler)282 JSTaggedValue ICRuntimeStub::StoreWithTS(JSThread *thread, JSTaggedValue receiver,
283 JSTaggedValue value, JSTaggedValue handler)
284 {
285 INTERPRETER_TRACE(thread, StoreWithAOT);
286 ASSERT(handler.IsStoreTSHandler());
287 StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(handler.GetTaggedObject());
288 auto cellValue = storeTSHandler->GetProtoCell();
289 ASSERT(cellValue.IsProtoChangeMarker());
290 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
291 if (cell->GetHasChanged()) {
292 return JSTaggedValue::Hole();
293 }
294 auto holder = storeTSHandler->GetHolder();
295 JSTaggedValue handlerInfo = storeTSHandler->GetHandlerInfo();
296 auto handlerInfoInt = static_cast<uint32_t>(handlerInfo.GetInt());
297 if (HandlerBase::IsField(handlerInfoInt)) {
298 StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfoInt);
299 return JSTaggedValue::Undefined();
300 }
301 ASSERT(HandlerBase::IsAccessor(handlerInfoInt) || HandlerBase::IsInternalAccessor(handlerInfoInt));
302 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfoInt);
303 return FastRuntimeStub::CallSetter(thread, JSTaggedValue(receiver), value, accessor);
304 }
305
StoreWithTransition(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler,bool withPrototype)306 void ICRuntimeStub::StoreWithTransition(JSThread *thread, JSObject *receiver, JSTaggedValue value,
307 JSTaggedValue handler, bool withPrototype)
308 {
309 INTERPRETER_TRACE(thread, StoreWithTransition);
310
311 JSHClass *newHClass = nullptr;
312 uint32_t handlerInfo = 0;
313
314 if (withPrototype) {
315 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
316 newHClass = JSHClass::Cast(transWithProtoHandler->GetTransitionHClass().GetTaggedObject());
317 handlerInfo = static_cast<uint32_t>(transWithProtoHandler->GetHandlerInfo().GetInt());
318 } else {
319 TransitionHandler *transitionHandler = TransitionHandler::Cast(handler.GetTaggedObject());
320 newHClass = JSHClass::Cast(transitionHandler->GetTransitionHClass().GetTaggedObject());
321 handlerInfo = static_cast<uint32_t>(transitionHandler->GetHandlerInfo().GetInt());
322 }
323
324 receiver->SynchronizedSetClass(thread, newHClass);
325 JSHandle<JSHClass> newHClassHandle(thread, newHClass);
326 JSHandle<JSObject> objHandle(thread, receiver);
327 JSHClass::TryRestoreElementsKind(thread, newHClassHandle, objHandle);
328 ASSERT(HandlerBase::IsField(handlerInfo));
329
330 if (!HandlerBase::IsInlinedProps(handlerInfo)) {
331 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
332 int capacity = static_cast<int>(array->GetLength());
333 int index = HandlerBase::GetOffset(handlerInfo);
334 if (index >= capacity) {
335 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
336 [[maybe_unused]] EcmaHandleScope handleScope(thread);
337 JSHandle<TaggedArray> properties;
338 JSHandle<JSTaggedValue> valueHandle(thread, value);
339 if (capacity == 0) {
340 capacity = JSObject::MIN_PROPERTIES_LENGTH;
341 properties = factory->NewTaggedArray(capacity);
342 } else {
343 auto arrayHandle = JSHandle<TaggedArray>(thread, array);
344 uint32_t maxNonInlinedFastPropsCapacity = objHandle->GetNonInlinedFastPropsCapacity();
345 uint32_t newLen = JSObject::ComputeNonInlinedFastPropsCapacity(thread, capacity,
346 maxNonInlinedFastPropsCapacity);
347 properties = factory->CopyArray(arrayHandle, capacity, newLen);
348 }
349 properties->Set(thread, index, valueHandle);
350 objHandle->SetProperties(thread, properties);
351 return;
352 }
353 array->Set(thread, index, value);
354 return;
355 }
356 StoreField(thread, receiver, value, handlerInfo);
357 }
358
StoreTransWithProto(JSThread * thread,JSObject * receiver,JSTaggedValue value,JSTaggedValue handler)359 JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *receiver, JSTaggedValue value,
360 JSTaggedValue handler)
361 {
362 INTERPRETER_TRACE(thread, StoreTransWithProto);
363 ASSERT(handler.IsTransWithProtoHandler());
364 TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject());
365 auto cellValue = transWithProtoHandler->GetProtoCell();
366 ASSERT(cellValue.IsProtoChangeMarker());
367 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
368 if (cell->GetHasChanged()) {
369 return JSTaggedValue::Hole();
370 }
371
372 StoreWithTransition(thread, receiver, value, handler, true);
373 return JSTaggedValue::Undefined();
374 }
375
StoreField(JSThread * thread,JSObject * receiver,JSTaggedValue value,uint32_t handler)376 ARK_INLINE void ICRuntimeStub::StoreField(JSThread *thread, JSObject *receiver, JSTaggedValue value, uint32_t handler)
377 {
378 INTERPRETER_TRACE(thread, StoreField);
379 int index = HandlerBase::GetOffset(handler);
380 if (HandlerBase::IsInlinedProps(handler)) {
381 SET_VALUE_WITH_BARRIER(thread, receiver, static_cast<uint32_t>(index) * JSTaggedValue::TaggedTypeSize(), value);
382 return;
383 }
384 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
385 ASSERT(index < static_cast<int>(array->GetLength()));
386 array->Set(thread, index, value);
387 }
388
LoadFromField(JSObject * receiver,uint32_t handlerInfo)389 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadFromField(JSObject *receiver, uint32_t handlerInfo)
390 {
391 int index = HandlerBase::GetOffset(handlerInfo);
392 if (HandlerBase::IsInlinedProps(handlerInfo)) {
393 return JSTaggedValue(GET_VALUE(receiver, static_cast<size_t>(index) * JSTaggedValue::TaggedTypeSize()));
394 }
395 return TaggedArray::Cast(receiver->GetProperties().GetTaggedObject())->Get(index);
396 }
397
LoadGlobal(JSTaggedValue handler)398 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadGlobal(JSTaggedValue handler)
399 {
400 ASSERT(handler.IsPropertyBox());
401 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
402 if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
403 return JSTaggedValue::Hole();
404 }
405 JSTaggedValue ret = cell->GetValue();
406 ASSERT(!ret.IsAccessorData());
407 return ret;
408 }
409
StoreGlobal(JSThread * thread,JSTaggedValue value,JSTaggedValue handler)410 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreGlobal(JSThread *thread, JSTaggedValue value, JSTaggedValue handler)
411 {
412 INTERPRETER_TRACE(thread, StoreGlobal);
413 ASSERT(handler.IsPropertyBox());
414 PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
415 if (cell->IsInvalid() || cell->GetValue().IsAccessorData()) {
416 return JSTaggedValue::Hole();
417 }
418 ASSERT(!cell->GetValue().IsAccessorData());
419 cell->SetValue(thread, value);
420 return JSTaggedValue::Undefined();
421 }
422
LoadPrototype(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler)423 JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue receiver, JSTaggedValue handler)
424 {
425 INTERPRETER_TRACE(thread, LoadPrototype);
426 ASSERT(handler.IsPrototypeHandler());
427 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
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 auto holder = prototypeHandler->GetHolder();
435 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
436 return LoadICWithHandler(thread, receiver, holder, handlerInfo);
437 }
438
LoadICWithHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue handler)439 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTaggedValue receiver,
440 JSTaggedValue holder, JSTaggedValue handler)
441 {
442 INTERPRETER_TRACE(thread, LoadICWithHandler);
443 if (LIKELY(handler.IsInt())) {
444 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
445 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
446 if (LIKELY(HandlerBase::IsField(handlerInfo))) {
447 if (!receiver.IsNumber()) {
448 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
449 }
450 ASSERT(receiver.IsNumber());
451 holder = env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype();
452 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
453 }
454 if (LIKELY(HandlerBase::IsString(handlerInfo))) {
455 holder = env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype();
456 return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
457 }
458 if (HandlerBase::IsNonExist(handlerInfo)) {
459 return JSTaggedValue::Undefined();
460 }
461 if (HandlerBase::IsStringLength(handlerInfo)) {
462 return JSTaggedNumber((EcmaStringAccessor(EcmaString::Cast(holder)).GetLength()));
463 }
464 ASSERT(HandlerBase::IsAccessor(handlerInfo) || HandlerBase::IsInternalAccessor(handlerInfo));
465 if (holder.IsString()) {
466 holder = env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype();
467 } else if (holder.IsNumber()) {
468 holder = env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype();
469 }
470 auto accessor = LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
471 return FastRuntimeStub::CallGetter(thread, receiver, holder, accessor);
472 }
473
474 if (handler.IsPrototypeHandler()) {
475 return LoadPrototype(thread, receiver, handler);
476 }
477
478 return LoadGlobal(handler);
479 }
480
LoadICWithElementHandler(JSThread * thread,JSTaggedValue receiver,JSTaggedValue handler,JSTaggedValue key)481 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *thread, JSTaggedValue receiver,
482 JSTaggedValue handler, JSTaggedValue key)
483 {
484 if (LIKELY(handler.IsInt())) {
485 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
486 if (HandlerBase::IsNormalElement(handlerInfo)) {
487 return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
488 } else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
489 return LoadTypedArrayElement(thread, receiver, key);
490 }
491 ASSERT(HandlerBase::IsStringElement(handlerInfo));
492 return LoadStringElement(thread, receiver, key);
493 }
494 return JSTaggedValue::Hole();
495 }
496
LoadElement(JSObject * receiver,JSTaggedValue key)497 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadElement(JSObject *receiver, JSTaggedValue key)
498 {
499 auto index = TryToElementsIndex(key);
500 if (index < 0) {
501 return JSTaggedValue::Hole();
502 }
503 uint32_t elementIndex = static_cast<uint32_t>(index);
504 if (ElementAccessor::GetElementsLength(receiver) <= elementIndex) {
505 return JSTaggedValue::Hole();
506 }
507
508 JSTaggedValue value = ElementAccessor::Get(receiver, elementIndex);
509 // TaggedArray elements
510 return value;
511 }
512
LoadStringElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)513 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
514 {
515 auto index = TryToElementsIndex(key);
516 if (index < 0) {
517 return JSTaggedValue::Hole();
518 }
519 uint32_t elementIndex = static_cast<uint32_t>(index);
520 uint16_t tmpChar = 0;
521 {
522 JSHandle<EcmaString> strHandle(thread, receiver);
523 JSHandle<EcmaString> strFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), strHandle));
524 if (EcmaStringAccessor(strFlat).GetLength() <= elementIndex) {
525 return JSTaggedValue::Hole();
526 }
527 tmpChar = EcmaStringAccessor(strFlat).Get(elementIndex);
528 }
529 auto factory = thread->GetEcmaVM()->GetFactory();
530 JSHandle<JSTaggedValue> value(factory->NewFromUtf16(&tmpChar, 1));
531 return value.GetTaggedValue();
532 }
533
LoadTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)534 ARK_INLINE JSTaggedValue ICRuntimeStub::LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
535 JSTaggedValue key)
536 {
537 auto index = TryToElementsIndex(key);
538 if (index < 0) {
539 return JSTaggedValue::Hole();
540 }
541 auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
542 uint32_t arrLen = typedarrayObj->GetArrayLength();
543 if (index >= arrLen) {
544 return JSTaggedValue::Hole();
545 }
546 JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
547 return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, type);
548 }
549
StoreElement(JSThread * thread,JSObject * receiver,JSTaggedValue key,JSTaggedValue value,JSTaggedValue handler)550 JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, JSTaggedValue key,
551 JSTaggedValue value, JSTaggedValue handler)
552 {
553 INTERPRETER_TRACE(thread, StoreElement);
554 auto index = TryToElementsIndex(key);
555 if (index < 0) {
556 return JSTaggedValue::Hole();
557 }
558 uint32_t elementIndex = static_cast<uint32_t>(index);
559 if (handler.IsInt()) {
560 auto handlerInfo = static_cast<uint32_t>(handler.GetInt());
561 [[maybe_unused]] EcmaHandleScope handleScope(thread);
562 JSHandle<JSObject> receiverHandle(thread, receiver);
563 if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
564 return StoreTypedArrayElement(thread, JSTaggedValue::Cast(receiver), key, value);
565 } else if (HandlerBase::IsJSArray(handlerInfo)) {
566 JSTaggedValue receiveValue = receiverHandle.GetTaggedValue();
567 if (receiveValue.IsJSCOWArray()) {
568 // Copy on write array.
569 JSArray::CheckAndCopyArray(thread, JSHandle<JSArray>::Cast(receiverHandle));
570 }
571 JSArray *arr = JSArray::Cast(*receiverHandle);
572 uint32_t oldLength = arr->GetArrayLength();
573 if (elementIndex >= oldLength) {
574 arr->SetArrayLength(thread, elementIndex + 1);
575 }
576 }
577 TaggedArray *elements = TaggedArray::Cast(receiverHandle->GetElements().GetTaggedObject());
578 uint32_t capacity = elements->GetLength();
579 if (elementIndex >= capacity) {
580 if (JSObject::ShouldTransToDict(capacity, elementIndex)) {
581 return JSTaggedValue::Hole();
582 }
583 JSHandle<JSTaggedValue> valueHandle(thread, value);
584 elements = *JSObject::GrowElementsCapacity(thread, receiverHandle, elementIndex + 1);
585 receiverHandle->SetElements(thread, JSTaggedValue(elements));
586 elements->Set(thread, elementIndex, valueHandle);
587 return JSTaggedValue::Undefined();
588 }
589 elements->Set(thread, elementIndex, value);
590 } else {
591 ASSERT(handler.IsPrototypeHandler());
592 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject());
593 auto cellValue = prototypeHandler->GetProtoCell();
594 ASSERT(cellValue.IsProtoChangeMarker());
595 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
596 if (cell->GetHasChanged()) {
597 return JSTaggedValue::Hole();
598 }
599 JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo();
600 return StoreElement(thread, receiver, key, value, handlerInfo);
601 }
602 return JSTaggedValue::Undefined();
603 }
604
StoreTypedArrayElement(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)605 ARK_INLINE JSTaggedValue ICRuntimeStub::StoreTypedArrayElement(JSThread *thread, JSTaggedValue receiver,
606 JSTaggedValue key, JSTaggedValue value)
607 {
608 auto index = TryToElementsIndex(key);
609 if (index < 0) {
610 return JSTaggedValue::Hole();
611 }
612 auto typedarrayObj = JSTypedArray::Cast(receiver.GetTaggedObject());
613 uint32_t arrLen = typedarrayObj->GetArrayLength();
614 if (index >= arrLen) {
615 return JSTaggedValue::Hole();
616 }
617 JSType type = typedarrayObj->GetJSHClass()->GetObjectType();
618 return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, type);
619 }
620
TryToElementsIndex(JSTaggedValue key)621 ARK_INLINE int64_t ICRuntimeStub::TryToElementsIndex(JSTaggedValue key)
622 {
623 if (LIKELY(key.IsInt())) {
624 return key.GetInt();
625 }
626
627 if (key.IsString()) {
628 uint32_t index = 0;
629 if (JSTaggedValue::StringToElementIndex(key, &index)) {
630 return static_cast<int64_t>(index);
631 }
632 }
633
634 if (key.IsDouble()) {
635 double number = key.GetDouble();
636 auto integer = static_cast<int32_t>(number);
637 if (number == integer) {
638 return integer;
639 }
640 }
641
642 return -1;
643 }
644
LoadMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)645 JSTaggedValue ICRuntimeStub::LoadMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
646 JSTaggedValue key, uint32_t slotId, ICKind kind)
647 {
648 [[maybe_unused]] EcmaHandleScope handleScope(thread);
649 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
650 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
651 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
652 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
653 return icRuntime.LoadMiss(receiverHandle, keyHandle);
654 }
655
LoadValueMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,uint32_t slotId,ICKind kind)656 JSTaggedValue ICRuntimeStub::LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
657 JSTaggedValue key, uint32_t slotId, ICKind kind)
658 {
659 [[maybe_unused]] EcmaHandleScope handleScope(thread);
660 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
661 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
662 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
663 LoadICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
664 return icRuntime.LoadValueMiss(receiverHandle, keyHandle);
665 }
666
StoreMiss(JSThread * thread,ProfileTypeInfo * profileTypeInfo,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,uint32_t slotId,ICKind kind,bool isOwn)667 JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
668 JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)
669 {
670 [[maybe_unused]] EcmaHandleScope handleScope(thread);
671 auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
672 auto receiverHandle = JSHandle<JSTaggedValue>(thread, receiver);
673 auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
674 auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
675 StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
676 return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle, isOwn);
677 }
678 } // namespace panda::ecmascript
679
680 #endif // ECMASCRIPT_IC_IC_RUNTIME_STUB_INL_H
681