1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
17 #define ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
18
19 #include "ecmascript/interpreter/fast_runtime_stub.h"
20
21 #include "ecmascript/global_dictionary-inl.h"
22 #include "ecmascript/global_env.h"
23 #include "ecmascript/internal_call_params.h"
24 #include "ecmascript/js_api_arraylist.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_hclass-inl.h"
27 #include "ecmascript/js_proxy.h"
28 #include "ecmascript/js_tagged_value-inl.h"
29 #include "ecmascript/js_typed_array.h"
30 #include "ecmascript/object_factory-inl.h"
31 #include "ecmascript/runtime_call_id.h"
32 #include "ecmascript/tagged_dictionary.h"
33
34 namespace panda::ecmascript {
FastAdd(JSTaggedValue left,JSTaggedValue right)35 JSTaggedValue FastRuntimeStub::FastAdd(JSTaggedValue left, JSTaggedValue right)
36 {
37 if (left.IsNumber() && right.IsNumber()) {
38 return JSTaggedValue(left.GetNumber() + right.GetNumber());
39 }
40
41 return JSTaggedValue::Hole();
42 }
43
FastSub(JSTaggedValue left,JSTaggedValue right)44 JSTaggedValue FastRuntimeStub::FastSub(JSTaggedValue left, JSTaggedValue right)
45 {
46 if (left.IsNumber() && right.IsNumber()) {
47 return JSTaggedValue(left.GetNumber() - right.GetNumber());
48 }
49
50 return JSTaggedValue::Hole();
51 }
52
FastMul(JSTaggedValue left,JSTaggedValue right)53 JSTaggedValue FastRuntimeStub::FastMul(JSTaggedValue left, JSTaggedValue right)
54 {
55 if (left.IsNumber() && right.IsNumber()) {
56 return JSTaggedValue(left.GetNumber() * right.GetNumber());
57 }
58
59 return JSTaggedValue::Hole();
60 }
61
FastDiv(JSTaggedValue left,JSTaggedValue right)62 JSTaggedValue FastRuntimeStub::FastDiv(JSTaggedValue left, JSTaggedValue right)
63 {
64 if (left.IsNumber() && right.IsNumber()) {
65 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
66 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
67 if (UNLIKELY(dRight == 0.0)) {
68 if (dLeft == 0.0 || std::isnan(dLeft)) {
69 return JSTaggedValue(base::NAN_VALUE);
70 }
71 uint64_t flagBit = ((bit_cast<uint64_t>(dLeft)) ^ (bit_cast<uint64_t>(dRight))) & base::DOUBLE_SIGN_MASK;
72 return JSTaggedValue(bit_cast<double>(flagBit ^ (bit_cast<uint64_t>(base::POSITIVE_INFINITY))));
73 }
74 return JSTaggedValue(dLeft / dRight);
75 }
76 return JSTaggedValue::Hole();
77 }
78
FastMod(JSTaggedValue left,JSTaggedValue right)79 JSTaggedValue FastRuntimeStub::FastMod(JSTaggedValue left, JSTaggedValue right)
80 {
81 if (right.IsInt() && left.IsInt()) {
82 int iRight = right.GetInt();
83 int iLeft = left.GetInt();
84 if (iRight > 0 && iLeft > 0) {
85 return JSTaggedValue(iLeft % iRight);
86 }
87 }
88 if (left.IsNumber() && right.IsNumber()) {
89 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
90 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
91 if (dRight == 0.0 || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
92 return JSTaggedValue(base::NAN_VALUE);
93 }
94 if (dLeft == 0.0 || std::isinf(dRight)) {
95 return JSTaggedValue(dLeft);
96 }
97 return JSTaggedValue(std::fmod(dLeft, dRight));
98 }
99 return JSTaggedValue::Hole();
100 }
101
FastEqual(JSTaggedValue left,JSTaggedValue right)102 JSTaggedValue FastRuntimeStub::FastEqual(JSTaggedValue left, JSTaggedValue right)
103 {
104 if (left == right) {
105 if (UNLIKELY(left.IsDouble())) {
106 return JSTaggedValue(!std::isnan(left.GetDouble()));
107 }
108 return JSTaggedValue::True();
109 }
110 if (left.IsNumber()) {
111 if (left.IsInt() && right.IsInt()) {
112 return JSTaggedValue::False();
113 }
114 }
115 if (right.IsUndefinedOrNull()) {
116 if (left.IsHeapObject()) {
117 return JSTaggedValue::False();
118 }
119 if (left.IsUndefinedOrNull()) {
120 return JSTaggedValue::True();
121 }
122 }
123 if (left.IsBoolean()) {
124 if (right.IsSpecial()) {
125 return JSTaggedValue::False();
126 }
127 }
128 if (left.IsBigInt() && right.IsBigInt()) {
129 return JSTaggedValue(BigInt::Equal(left, right));
130 }
131 return JSTaggedValue::Hole();
132 }
133
FastStrictEqual(JSTaggedValue left,JSTaggedValue right)134 bool FastRuntimeStub::FastStrictEqual(JSTaggedValue left, JSTaggedValue right)
135 {
136 if (left.IsNumber()) {
137 if (right.IsNumber()) {
138 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
139 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
140 return JSTaggedValue::StrictNumberEquals(dLeft, dRight);
141 }
142 return false;
143 }
144 if (right.IsNumber()) {
145 return false;
146 }
147 if (left == right) {
148 return true;
149 }
150 if (left.IsString() && right.IsString()) {
151 return EcmaString::StringsAreEqual(static_cast<EcmaString *>(left.GetTaggedObject()),
152 static_cast<EcmaString *>(right.GetTaggedObject()));
153 }
154 if (left.IsBigInt()) {
155 if (right.IsBigInt()) {
156 return BigInt::Equal(left, right);
157 }
158 return false;
159 }
160 if (right.IsBigInt()) {
161 return false;
162 }
163 return false;
164 }
165
IsSpecialIndexedObj(JSType jsType)166 bool FastRuntimeStub::IsSpecialIndexedObj(JSType jsType)
167 {
168 return jsType > JSType::JS_ARRAY;
169 }
170
IsSpecialReceiverObj(JSType jsType)171 bool FastRuntimeStub::IsSpecialReceiverObj(JSType jsType)
172 {
173 return jsType > JSType::JS_PRIMITIVE_REF;
174 }
175
IsSpecialContainer(JSType jsType)176 bool FastRuntimeStub::IsSpecialContainer(JSType jsType)
177 {
178 return jsType >= JSType::JS_API_ARRAY_LIST && jsType <= JSType::JS_QUEUE;
179 }
180
TryToElementsIndex(JSTaggedValue key)181 int32_t FastRuntimeStub::TryToElementsIndex(JSTaggedValue key)
182 {
183 if (LIKELY(key.IsInt())) {
184 return key.GetInt();
185 }
186 if (key.IsString()) {
187 uint32_t index = 0;
188 if (JSTaggedValue::StringToElementIndex(key, &index)) {
189 return static_cast<int32_t>(index);
190 }
191 } else if (key.IsDouble()) {
192 double number = key.GetDouble();
193 auto integer = static_cast<int32_t>(number);
194 if (number == integer) {
195 return integer;
196 }
197 }
198 return -1;
199 }
200
CallGetter(JSThread * thread,JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue value)201 JSTaggedValue FastRuntimeStub::CallGetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
202 JSTaggedValue value)
203 {
204 INTERPRETER_TRACE(thread, CallGetter);
205 // Accessor
206 [[maybe_unused]] EcmaHandleScope handleScope(thread);
207 AccessorData *accessor = AccessorData::Cast(value.GetTaggedObject());
208 if (UNLIKELY(accessor->IsInternal())) {
209 JSHandle<JSObject> objHandle(thread, holder);
210 return accessor->CallInternalGet(thread, objHandle);
211 }
212 JSHandle<JSTaggedValue> objHandle(thread, receiver);
213 return JSObject::CallGetter(thread, accessor, objHandle);
214 }
215
CallSetter(JSThread * thread,JSTaggedValue receiver,JSTaggedValue value,JSTaggedValue accessorValue)216 JSTaggedValue FastRuntimeStub::CallSetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value,
217 JSTaggedValue accessorValue)
218 {
219 INTERPRETER_TRACE(thread, CallSetter);
220 // Accessor
221 [[maybe_unused]] EcmaHandleScope handleScope(thread);
222 JSHandle<JSTaggedValue> objHandle(thread, receiver);
223 JSHandle<JSTaggedValue> valueHandle(thread, value);
224
225 auto accessor = AccessorData::Cast(accessorValue.GetTaggedObject());
226 bool success = JSObject::CallSetter(thread, *accessor, objHandle, valueHandle, true);
227 return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
228 }
229
ShouldCallSetter(JSTaggedValue receiver,JSTaggedValue holder,JSTaggedValue accessorValue,PropertyAttributes attr)230 bool FastRuntimeStub::ShouldCallSetter(JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue accessorValue,
231 PropertyAttributes attr)
232 {
233 if (!AccessorData::Cast(accessorValue.GetTaggedObject())->IsInternal()) {
234 return true;
235 }
236 if (receiver != holder) {
237 return false;
238 }
239 return attr.IsWritable();
240 }
241
AddPropertyByName(JSThread * thread,JSHandle<JSObject> objHandle,JSHandle<JSTaggedValue> keyHandle,JSHandle<JSTaggedValue> valueHandle,PropertyAttributes attr)242 PropertyAttributes FastRuntimeStub::AddPropertyByName(JSThread *thread, JSHandle<JSObject> objHandle,
243 JSHandle<JSTaggedValue> keyHandle,
244 JSHandle<JSTaggedValue> valueHandle,
245 PropertyAttributes attr)
246 {
247 INTERPRETER_TRACE(thread, AddPropertyByName);
248
249 if (objHandle->IsJSArray() && keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()) {
250 objHandle->GetJSHClass()->SetHasConstructor(true);
251 }
252 int32_t nextInlinedPropsIndex = objHandle->GetJSHClass()->GetNextInlinedPropsIndex();
253 if (nextInlinedPropsIndex >= 0) {
254 objHandle->SetPropertyInlinedProps(thread, nextInlinedPropsIndex, valueHandle.GetTaggedValue());
255 attr.SetOffset(nextInlinedPropsIndex);
256 attr.SetIsInlinedProps(true);
257 JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
258 return attr;
259 }
260
261 JSMutableHandle<TaggedArray> array(thread, objHandle->GetProperties());
262 uint32_t length = array->GetLength();
263 if (length == 0) {
264 length = JSObject::MIN_PROPERTIES_LENGTH;
265 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
266 array.Update(factory->NewTaggedArray(length).GetTaggedValue());
267 objHandle->SetProperties(thread, array.GetTaggedValue());
268 }
269
270 if (!array->IsDictionaryMode()) {
271 attr.SetIsInlinedProps(false);
272
273 uint32_t nonInlinedProps = objHandle->GetJSHClass()->GetNextNonInlinedPropsIndex();
274 ASSERT(length >= nonInlinedProps);
275 // if array is full, grow array or change to dictionary mode
276 if (length == nonInlinedProps) {
277 if (UNLIKELY(length == JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)) {
278 // change to dictionary and add one.
279 JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread, objHandle));
280 JSHandle<NameDictionary> newDict =
281 NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
282 objHandle->SetProperties(thread, newDict);
283 // index is not essential when fastMode is false;
284 return attr;
285 }
286 // Grow properties array size
287 uint32_t capacity = JSObject::ComputePropertyCapacity(length);
288 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
289 array.Update(factory->CopyArray(array, length, capacity).GetTaggedValue());
290 objHandle->SetProperties(thread, array.GetTaggedValue());
291 }
292
293 attr.SetOffset(nonInlinedProps + objHandle->GetJSHClass()->GetInlinedProperties());
294 JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
295 array->Set(thread, nonInlinedProps, valueHandle.GetTaggedValue());
296 } else {
297 JSHandle<NameDictionary> dictHandle(array);
298 JSHandle<NameDictionary> newDict =
299 NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr);
300 objHandle->SetProperties(thread, newDict);
301 }
302 return attr;
303 }
304
AddPropertyByIndex(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value)305 JSTaggedValue FastRuntimeStub::AddPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
306 JSTaggedValue value)
307 {
308 INTERPRETER_TRACE(thread, AddPropertyByIndex);
309 [[maybe_unused]] EcmaHandleScope handleScope(thread);
310 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
311 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
312 }
313
314 bool success = JSObject::AddElementInternal(thread, JSHandle<JSObject>(thread, receiver), index,
315 JSHandle<JSTaggedValue>(thread, value), PropertyAttributes::Default());
316 return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
317 }
318
319 template<bool UseOwn>
GetPropertyByIndex(JSThread * thread,JSTaggedValue receiver,uint32_t index)320 JSTaggedValue FastRuntimeStub::GetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
321 {
322 INTERPRETER_TRACE(thread, GetPropertyByIndex);
323 [[maybe_unused]] EcmaHandleScope handleScope(thread);
324 JSTaggedValue holder = receiver;
325 do {
326 auto *hclass = holder.GetTaggedObject()->GetClass();
327 JSType jsType = hclass->GetObjectType();
328 if (IsSpecialIndexedObj(jsType)) {
329 if (IsSpecialContainer(jsType)) {
330 return GetContainerProperty(thread, holder, index, jsType);
331 }
332 return JSTaggedValue::Hole();
333 }
334 TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(holder)->GetElements().GetTaggedObject());
335
336 if (!hclass->IsDictionaryElement()) {
337 ASSERT(!elements->IsDictionaryMode());
338 if (index < elements->GetLength()) {
339 JSTaggedValue value = elements->Get(index);
340 if (!value.IsHole()) {
341 return value;
342 }
343 } else {
344 return JSTaggedValue::Hole();
345 }
346 } else {
347 NumberDictionary *dict = NumberDictionary::Cast(elements);
348 int entry = dict->FindEntry(JSTaggedValue(static_cast<int>(index)));
349 if (entry != -1) {
350 auto attr = dict->GetAttributes(entry);
351 auto value = dict->GetValue(entry);
352 if (UNLIKELY(attr.IsAccessor())) {
353 return CallGetter(thread, receiver, holder, value);
354 }
355 ASSERT(!value.IsAccessor());
356 return value;
357 }
358 }
359 if (UseOwn) {
360 break;
361 }
362 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
363 } while (holder.IsHeapObject());
364
365 // not found
366 return JSTaggedValue::Undefined();
367 }
368
369 template<bool UseOwn>
GetPropertyByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)370 JSTaggedValue FastRuntimeStub::GetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
371 {
372 INTERPRETER_TRACE(thread, GetPropertyByValue);
373 if (UNLIKELY(!key.IsNumber() && !key.IsStringOrSymbol())) {
374 return JSTaggedValue::Hole();
375 }
376 // fast path
377 auto index = TryToElementsIndex(key);
378 if (LIKELY(index >= 0)) {
379 return GetPropertyByIndex<UseOwn>(thread, receiver, index);
380 }
381 if (!key.IsNumber()) {
382 if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
383 // update string stable
384 [[maybe_unused]] EcmaHandleScope handleScope(thread);
385 JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
386 key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
387 // Maybe moved by GC
388 receiver = receiverHandler.GetTaggedValue();
389 }
390 return FastRuntimeStub::GetPropertyByName<UseOwn>(thread, receiver, key);
391 }
392 return JSTaggedValue::Hole();
393 }
394
395 template<bool UseOwn>
GetPropertyByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)396 JSTaggedValue FastRuntimeStub::GetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
397 {
398 INTERPRETER_TRACE(thread, GetPropertyByName);
399 // no gc when return hole
400 ASSERT(key.IsStringOrSymbol());
401 JSTaggedValue holder = receiver;
402 do {
403 auto *hclass = holder.GetTaggedObject()->GetClass();
404 JSType jsType = hclass->GetObjectType();
405 if (IsSpecialIndexedObj(jsType)) {
406 return JSTaggedValue::Hole();
407 }
408
409 if (LIKELY(!hclass->IsDictionaryMode())) {
410 ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
411
412 LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
413 int propsNumber = hclass->NumberOfProps();
414 int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
415 if (entry != -1) {
416 PropertyAttributes attr(layoutInfo->GetAttr(entry));
417 ASSERT(static_cast<int>(attr.GetOffset()) == entry);
418 auto value = JSObject::Cast(holder)->GetProperty(hclass, attr);
419 if (UNLIKELY(attr.IsAccessor())) {
420 return CallGetter(thread, receiver, holder, value);
421 }
422 ASSERT(!value.IsAccessor());
423 return value;
424 }
425 } else {
426 TaggedArray *array = TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject());
427 ASSERT(array->IsDictionaryMode());
428 NameDictionary *dict = NameDictionary::Cast(array);
429 int entry = dict->FindEntry(key);
430 if (entry != -1) {
431 auto value = dict->GetValue(entry);
432 auto attr = dict->GetAttributes(entry);
433 if (UNLIKELY(attr.IsAccessor())) {
434 return CallGetter(thread, receiver, holder, value);
435 }
436 ASSERT(!value.IsAccessor());
437 return value;
438 }
439 }
440 if (UseOwn) {
441 break;
442 }
443 holder = hclass->GetPrototype();
444 } while (holder.IsHeapObject());
445 // not found
446 return JSTaggedValue::Undefined();
447 }
448
449 template<bool UseOwn>
SetPropertyByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)450 JSTaggedValue FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
451 JSTaggedValue value)
452 {
453 INTERPRETER_TRACE(thread, SetPropertyByName);
454 // property
455 JSTaggedValue holder = receiver;
456 do {
457 auto *hclass = holder.GetTaggedObject()->GetClass();
458 JSType jsType = hclass->GetObjectType();
459 if (IsSpecialIndexedObj(jsType)) {
460 if (IsSpecialContainer(jsType)) {
461 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", JSTaggedValue::Exception());
462 }
463 return JSTaggedValue::Hole();
464 }
465 // UpdateRepresentation
466 if (LIKELY(!hclass->IsDictionaryMode())) {
467 ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
468
469 LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
470
471 int propsNumber = hclass->NumberOfProps();
472 int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
473 if (entry != -1) {
474 PropertyAttributes attr(layoutInfo->GetAttr(entry));
475 ASSERT(static_cast<int>(attr.GetOffset()) == entry);
476 if (UNLIKELY(attr.IsAccessor())) {
477 auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr);
478 if (ShouldCallSetter(receiver, holder, accessor, attr)) {
479 return CallSetter(thread, receiver, value, accessor);
480 }
481 }
482 if (UNLIKELY(!attr.IsWritable())) {
483 [[maybe_unused]] EcmaHandleScope handleScope(thread);
484 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", JSTaggedValue::Exception());
485 }
486 if (UNLIKELY(holder != receiver)) {
487 break;
488 }
489 JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value);
490 return JSTaggedValue::Undefined();
491 }
492 } else {
493 TaggedArray *properties = TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject());
494 ASSERT(properties->IsDictionaryMode());
495 NameDictionary *dict = NameDictionary::Cast(properties);
496 int entry = dict->FindEntry(key);
497 if (entry != -1) {
498 auto attr = dict->GetAttributes(entry);
499 if (UNLIKELY(attr.IsAccessor())) {
500 auto accessor = dict->GetValue(entry);
501 if (ShouldCallSetter(receiver, holder, accessor, attr)) {
502 return CallSetter(thread, receiver, value, accessor);
503 }
504 }
505 if (UNLIKELY(!attr.IsWritable())) {
506 [[maybe_unused]] EcmaHandleScope handleScope(thread);
507 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", JSTaggedValue::Exception());
508 }
509 if (UNLIKELY(holder != receiver)) {
510 break;
511 }
512 dict->UpdateValue(thread, entry, value);
513 return JSTaggedValue::Undefined();
514 }
515 }
516 if (UseOwn) {
517 break;
518 }
519 holder = hclass->GetPrototype();
520 } while (holder.IsHeapObject());
521
522 [[maybe_unused]] EcmaHandleScope handleScope(thread);
523 JSHandle<JSObject> objHandle(thread, receiver);
524 JSHandle<JSTaggedValue> keyHandle(thread, key);
525 JSHandle<JSTaggedValue> valueHandle(thread, value);
526
527 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
528 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
529 }
530 AddPropertyByName(thread, objHandle, keyHandle, valueHandle, PropertyAttributes::Default());
531 return JSTaggedValue::Undefined();
532 }
533
534 template<bool UseOwn>
SetPropertyByIndex(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value)535 JSTaggedValue FastRuntimeStub::SetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
536 JSTaggedValue value)
537 {
538 INTERPRETER_TRACE(thread, SetPropertyByIndex);
539 JSTaggedValue holder = receiver;
540 do {
541 auto *hclass = holder.GetTaggedObject()->GetClass();
542 JSType jsType = hclass->GetObjectType();
543 if (IsSpecialIndexedObj(jsType)) {
544 if (IsSpecialContainer(jsType)) {
545 return SetContainerProperty(thread, holder, index, value, jsType);
546 }
547 return JSTaggedValue::Hole();
548 }
549 TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(holder)->GetElements().GetTaggedObject());
550 if (!hclass->IsDictionaryElement()) {
551 ASSERT(!elements->IsDictionaryMode());
552 if (UNLIKELY(holder != receiver)) {
553 break;
554 }
555 if (index < elements->GetLength()) {
556 if (!elements->Get(index).IsHole()) {
557 elements->Set(thread, index, value);
558 return JSTaggedValue::Undefined();
559 }
560 }
561 } else {
562 return JSTaggedValue::Hole();
563 }
564 if (UseOwn) {
565 break;
566 }
567 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
568 } while (holder.IsHeapObject());
569
570 return AddPropertyByIndex(thread, receiver, index, value);
571 }
572
573 template<bool UseOwn>
SetPropertyByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)574 JSTaggedValue FastRuntimeStub::SetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
575 JSTaggedValue value)
576 {
577 INTERPRETER_TRACE(thread, SetPropertyByValue);
578 if (UNLIKELY(!key.IsNumber() && !key.IsStringOrSymbol())) {
579 return JSTaggedValue::Hole();
580 }
581 // fast path
582 auto index = TryToElementsIndex(key);
583 if (LIKELY(index >= 0)) {
584 return SetPropertyByIndex<UseOwn>(thread, receiver, index, value);
585 }
586 if (!key.IsNumber()) {
587 if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
588 // update string stable
589 [[maybe_unused]] EcmaHandleScope handleScope(thread);
590 JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
591 JSHandle<JSTaggedValue> valueHandler(thread, value);
592 key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
593 // Maybe moved by GC
594 receiver = receiverHandler.GetTaggedValue();
595 value = valueHandler.GetTaggedValue();
596 }
597 return FastRuntimeStub::SetPropertyByName<UseOwn>(thread, receiver, key, value);
598 }
599 return JSTaggedValue::Hole();
600 }
601
GetGlobalOwnProperty(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)602 JSTaggedValue FastRuntimeStub::GetGlobalOwnProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
603 {
604 JSObject *obj = JSObject::Cast(receiver);
605 TaggedArray *properties = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
606 GlobalDictionary *dict = GlobalDictionary::Cast(properties);
607 int entry = dict->FindEntry(key);
608 if (entry != -1) {
609 auto value = dict->GetValue(entry);
610 if (UNLIKELY(value.IsAccessor())) {
611 return CallGetter(thread, receiver, receiver, value);
612 }
613 ASSERT(!value.IsAccessor());
614 return value;
615 }
616 return JSTaggedValue::Hole();
617 }
618
FastTypeOf(JSThread * thread,JSTaggedValue obj)619 JSTaggedValue FastRuntimeStub::FastTypeOf(JSThread *thread, JSTaggedValue obj)
620 {
621 INTERPRETER_TRACE(thread, FastTypeOf);
622 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
623 switch (obj.GetRawData()) {
624 case JSTaggedValue::VALUE_TRUE:
625 case JSTaggedValue::VALUE_FALSE:
626 return globalConst->GetBooleanString();
627 case JSTaggedValue::VALUE_NULL:
628 return globalConst->GetObjectString();
629 case JSTaggedValue::VALUE_UNDEFINED:
630 return globalConst->GetUndefinedString();
631 default:
632 if (obj.IsHeapObject()) {
633 if (obj.IsString()) {
634 return globalConst->GetStringString();
635 }
636 if (obj.IsSymbol()) {
637 return globalConst->GetSymbolString();
638 }
639 if (obj.IsCallable()) {
640 return globalConst->GetFunctionString();
641 }
642 if (obj.IsBigInt()) {
643 return globalConst->GetBigIntString();
644 }
645 return globalConst->GetObjectString();
646 }
647 if (obj.IsNumber()) {
648 return globalConst->GetNumberString();
649 }
650 }
651 return globalConst->GetUndefinedString();
652 }
653
FastSetPropertyByIndex(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value)654 bool FastRuntimeStub::FastSetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
655 JSTaggedValue value)
656 {
657 INTERPRETER_TRACE(thread, FastSetPropertyByIndex);
658 #ifdef ECMASCRIPT_ENABLE_STUB_AOT1
659 auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(SetPropertyByIndex));
660 typedef JSTaggedValue (*PFSetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t, JSTaggedValue);
661 auto setPropertyByIndex = reinterpret_cast<PFSetPropertyByIndex>(stubAddr);
662 JSTaggedValue result = setPropertyByIndex(thread->GetGlueAddr(), receiver, index, value);
663 #else
664 JSTaggedValue result = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value);
665 #endif
666 if (!result.IsHole()) {
667 return result != JSTaggedValue::Exception();
668 }
669 return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver), index,
670 JSHandle<JSTaggedValue>(thread, value), true);
671 }
672
FastSetPropertyByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)673 bool FastRuntimeStub::FastSetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
674 JSTaggedValue value)
675 {
676 INTERPRETER_TRACE(thread, FastSetPropertyByValue);
677 JSTaggedValue result = FastRuntimeStub::SetPropertyByValue(thread, receiver, key, value);
678 if (!result.IsHole()) {
679 return result != JSTaggedValue::Exception();
680 }
681 return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
682 JSHandle<JSTaggedValue>(thread, key), JSHandle<JSTaggedValue>(thread, value),
683 true);
684 }
685
686 // must not use for interpreter
FastGetPropertyByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)687 JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
688 {
689 INTERPRETER_TRACE(thread, FastGetPropertyByName);
690 ASSERT(key.IsStringOrSymbol());
691 if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
692 JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
693 key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
694 // Maybe moved by GC
695 receiver = receiverHandler.GetTaggedValue();
696 }
697 #ifdef ECMASCRIPT_ENABLE_STUB_AOT1
698 auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByName));
699 typedef JSTaggedValue (*PFGetPropertyByName)(uintptr_t, JSTaggedValue, JSTaggedValue);
700 auto getPropertyByNamePtr = reinterpret_cast<PFGetPropertyByName>(stubAddr);
701 JSTaggedValue result = getPropertyByNamePtr(thread->GetGlueAddr(), receiver, key);
702 #else
703 JSTaggedValue result = FastRuntimeStub::GetPropertyByName(thread, receiver, key);
704 #endif
705 if (result.IsHole()) {
706 return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
707 JSHandle<JSTaggedValue>(thread, key))
708 .GetValue()
709 .GetTaggedValue();
710 }
711 return result;
712 }
713
FastGetPropertyByValue(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)714 JSTaggedValue FastRuntimeStub::FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
715 {
716 INTERPRETER_TRACE(thread, FastGetPropertyByValue);
717 #ifdef ECMASCRIPT_ENABLE_STUB_AOT1
718 auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByValue));
719 typedef JSTaggedValue (*PFGetPropertyByValue)(uintptr_t, JSTaggedValue, JSTaggedValue);
720 auto getPropertyByValuePtr = reinterpret_cast<PFGetPropertyByValue>(stubAddr);
721 JSTaggedValue result = getPropertyByValuePtr(thread->GetGlueAddr(), receiver, key);
722 #else
723 JSTaggedValue result = FastRuntimeStub::GetPropertyByValue(thread, receiver, key);
724 #endif
725 if (result.IsHole()) {
726 return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
727 JSHandle<JSTaggedValue>(thread, key))
728 .GetValue()
729 .GetTaggedValue();
730 }
731 return result;
732 }
733
734 template<bool UseHole> // UseHole is only for Array::Sort() which requires Hole order
FastGetPropertyByIndex(JSThread * thread,JSTaggedValue receiver,uint32_t index)735 JSTaggedValue FastRuntimeStub::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
736 {
737 INTERPRETER_TRACE(thread, FastGetPropertyByIndex);
738 #ifdef ECMASCRIPT_ENABLE_STUB_AOT1
739 auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex));
740 typedef JSTaggedValue (*PFGetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t);
741 auto getPropertyByIndex = reinterpret_cast<PFGetPropertyByIndex>(stubAddr);
742 JSTaggedValue result = getPropertyByIndex(thread->GetGlueAddr(), receiver, index);
743 #else
744 JSTaggedValue result = FastRuntimeStub::GetPropertyByIndex(thread, receiver, index);
745 #endif
746 if (result.IsHole() && !UseHole) {
747 return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver), index)
748 .GetValue()
749 .GetTaggedValue();
750 }
751 return result;
752 }
753
NewLexicalEnvDyn(JSThread * thread,ObjectFactory * factory,uint16_t numVars)754 JSTaggedValue FastRuntimeStub::NewLexicalEnvDyn(JSThread *thread, ObjectFactory *factory, uint16_t numVars)
755 {
756 INTERPRETER_TRACE(thread, NewLexicalEnvDyn);
757 [[maybe_unused]] EcmaHandleScope handleScope(thread);
758 LexicalEnv *newEnv = factory->InlineNewLexicalEnv(numVars);
759 if (UNLIKELY(newEnv == nullptr)) {
760 return JSTaggedValue::Hole();
761 }
762 JSTaggedValue currentLexenv = thread->GetCurrentLexenv();
763 newEnv->SetParentEnv(thread, currentLexenv);
764 newEnv->SetScopeInfo(thread, JSTaggedValue::Hole());
765 return JSTaggedValue(newEnv);
766 }
767
768 // Those interface below is discarded
IsSpecialIndexedObjForGet(JSTaggedValue obj)769 bool FastRuntimeStub::IsSpecialIndexedObjForGet(JSTaggedValue obj)
770 {
771 JSType jsType = obj.GetTaggedObject()->GetClass()->GetObjectType();
772 return jsType > JSType::JS_ARRAY && jsType <= JSType::JS_PRIMITIVE_REF;
773 }
774
IsSpecialIndexedObjForSet(JSTaggedValue obj)775 bool FastRuntimeStub::IsSpecialIndexedObjForSet(JSTaggedValue obj)
776 {
777 JSType jsType = obj.GetTaggedObject()->GetClass()->GetObjectType();
778 return jsType >= JSType::JS_ARRAY && jsType <= JSType::JS_PRIMITIVE_REF;
779 }
780
GetElement(JSTaggedValue receiver,uint32_t index)781 JSTaggedValue FastRuntimeStub::GetElement(JSTaggedValue receiver, uint32_t index)
782 {
783 JSTaggedValue holder = receiver;
784 while (true) {
785 JSTaggedValue val = FindOwnElement(JSObject::Cast(holder), index);
786 if (!val.IsHole()) {
787 return val;
788 }
789
790 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
791 if (!holder.IsHeapObject()) {
792 return JSTaggedValue::Undefined();
793 }
794 }
795 }
796
GetElementWithArray(JSTaggedValue receiver,uint32_t index)797 JSTaggedValue FastRuntimeStub::GetElementWithArray(JSTaggedValue receiver, uint32_t index)
798 {
799 DISALLOW_GARBAGE_COLLECTION;
800 JSTaggedValue holder = receiver;
801 while (true) {
802 JSTaggedValue val = FindOwnElement(JSObject::Cast(holder), index);
803 if (!val.IsHole()) {
804 return val;
805 }
806
807 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
808 if (!holder.IsHeapObject()) {
809 return val;
810 }
811 }
812 }
813
SetElement(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value,bool mayThrow)814 bool FastRuntimeStub::SetElement(JSThread *thread, JSTaggedValue receiver, uint32_t index, JSTaggedValue value,
815 bool mayThrow)
816 {
817 INTERPRETER_TRACE(thread, SetElement);
818 JSTaggedValue holder = receiver;
819 bool onPrototype = false;
820
821 while (true) {
822 PropertyAttributes attr;
823 uint32_t indexOrEntry = 0;
824 TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(holder)->GetElements().GetHeapObject());
825 bool isDict = elements->IsDictionaryMode();
826 JSTaggedValue val = FindOwnElement(elements, index, isDict, &attr, &indexOrEntry);
827 if (!val.IsHole()) {
828 if (UNLIKELY(onPrototype)) {
829 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
830 if (mayThrow) {
831 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", false);
832 }
833 return false;
834 }
835
836 return JSObject::AddElementInternal(thread, JSHandle<JSObject>(thread, receiver), index,
837 JSHandle<JSTaggedValue>(thread, value),
838 PropertyAttributes::Default());
839 }
840 if (!attr.IsAccessor()) {
841 if (attr.IsWritable()) {
842 elements = TaggedArray::Cast(JSObject::Cast(receiver)->GetElements().GetHeapObject());
843 if (!isDict) {
844 elements->Set(thread, indexOrEntry, value);
845 JSObject::Cast(receiver)->GetJSHClass()->UpdateRepresentation(value);
846 return true;
847 }
848 NumberDictionary::Cast(elements)->UpdateValueAndAttributes(thread, indexOrEntry, value, attr);
849 return true;
850 }
851
852 if (mayThrow) {
853 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", false);
854 }
855 return false;
856 }
857
858 // Accessor
859 [[maybe_unused]] EcmaHandleScope handleScope(thread);
860 JSHandle<JSTaggedValue> objHandle(thread, receiver);
861 JSHandle<JSTaggedValue> valueHandle(thread, value);
862 AccessorData *access = AccessorData::Cast(val.GetHeapObject());
863 return JSObject::CallSetter(thread, *access, objHandle, valueHandle, mayThrow);
864 }
865
866 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
867 if (!holder.IsHeapObject()) {
868 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
869 if (mayThrow) {
870 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", false);
871 }
872 return false;
873 }
874
875 return JSObject::AddElementInternal(thread, JSHandle<JSObject>(thread, receiver), index,
876 JSHandle<JSTaggedValue>(thread, value), PropertyAttributes::Default());
877 }
878 if (holder.IsJSProxy()) {
879 return JSProxy::SetProperty(
880 thread, JSHandle<JSProxy>(thread, holder), JSHandle<JSTaggedValue>(thread, JSTaggedValue(index)),
881 JSHandle<JSTaggedValue>(thread, value), JSHandle<JSTaggedValue>(thread, receiver), mayThrow);
882 }
883 onPrototype = true;
884 }
885 }
886
SetPropertyByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,bool mayThrow)887 bool FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
888 JSTaggedValue value, bool mayThrow)
889 {
890 INTERPRETER_TRACE(thread, SetPropertyByName);
891 // property
892 JSTaggedValue holder = receiver;
893 bool onPrototype = false;
894
895 while (true) {
896 TaggedArray *properties = TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetHeapObject());
897 PropertyAttributes attr;
898 uint32_t indexOrEntry = 0;
899 JSTaggedValue val = FindOwnProperty(thread, JSObject::Cast(holder), properties, key, &attr, &indexOrEntry);
900 if (!val.IsHole()) {
901 if (!attr.IsAccessor()) {
902 if (UNLIKELY(onPrototype)) {
903 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible() || !attr.IsWritable())) {
904 if (mayThrow) {
905 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", false);
906 }
907 return false;
908 }
909 [[maybe_unused]] EcmaHandleScope handleScope(thread);
910 ObjectOperator::FastAdd(thread, receiver, key, JSHandle<JSTaggedValue>(thread, value),
911 PropertyAttributes::Default());
912
913 return true;
914 }
915
916 if (attr.IsWritable()) {
917 properties = TaggedArray::Cast(JSObject::Cast(receiver)->GetProperties().GetHeapObject());
918 if (!properties->IsDictionaryMode()) {
919 Representation representation =
920 PropertyAttributes::UpdateRepresentation(attr.GetRepresentation(), value);
921 if (attr.GetRepresentation() != representation) {
922 attr.SetRepresentation(representation);
923 }
924
925 JSObject::Cast(receiver)->GetJSHClass()->UpdatePropertyMetaData(thread, key, attr);
926 if (UNLIKELY(val.IsInternalAccessor())) {
927 [[maybe_unused]] EcmaHandleScope handleScope(thread);
928 AccessorData::Cast(val.GetHeapObject())
929 ->CallInternalSet(thread, JSHandle<JSObject>(thread, receiver),
930 JSHandle<JSTaggedValue>(thread, value), mayThrow);
931 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
932 return true;
933 }
934
935 if (attr.IsInlinedProps()) {
936 JSObject::Cast(receiver)->SetPropertyInlinedProps(thread, indexOrEntry, value);
937 } else {
938 properties->Set(thread, indexOrEntry, value);
939 }
940 return true;
941 }
942
943 if (receiver.IsJSGlobalObject()) {
944 [[maybe_unused]] EcmaHandleScope handleScope(thread);
945 JSHandle<GlobalDictionary> dictHandle(thread, properties);
946 // globalobj have no internal accessor
947 GlobalDictionary::InvalidatePropertyBox(thread, dictHandle, indexOrEntry, attr);
948 return true;
949 }
950
951 if (UNLIKELY(val.IsInternalAccessor())) {
952 [[maybe_unused]] EcmaHandleScope handleScope(thread);
953 AccessorData::Cast(val.GetHeapObject())
954 ->CallInternalSet(thread, JSHandle<JSObject>(thread, receiver),
955 JSHandle<JSTaggedValue>(thread, value), mayThrow);
956 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
957 return true;
958 }
959
960 NameDictionary::Cast(properties)->UpdateValueAndAttributes(thread, indexOrEntry, value, attr);
961 return true;
962 }
963
964 if (mayThrow) {
965 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", false);
966 }
967 return false;
968 }
969
970 // Accessor
971 [[maybe_unused]] EcmaHandleScope handleScope(thread);
972 JSHandle<JSTaggedValue> objHandle(thread, receiver);
973 JSHandle<JSTaggedValue> valueHandle(thread, value);
974 AccessorData *access = AccessorData::Cast(val.GetHeapObject());
975 return JSObject::CallSetter(thread, *access, objHandle, valueHandle, mayThrow);
976 }
977
978 if (holder.IsTypedArray()) {
979 [[maybe_unused]] EcmaHandleScope handleScope(thread);
980 return JSTypedArray::SetProperty(thread, JSHandle<JSTaggedValue>(thread, holder),
981 JSTypedArray::ToPropKey(thread, JSHandle<JSTaggedValue>(thread, key)),
982 JSHandle<JSTaggedValue>(thread, value),
983 JSHandle<JSTaggedValue>(thread, receiver), mayThrow);
984 }
985
986 holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
987 if (!holder.IsHeapObject()) {
988 if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
989 if (mayThrow) {
990 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", false);
991 }
992 return false;
993 }
994 [[maybe_unused]] EcmaHandleScope handleScope(thread);
995 ObjectOperator::FastAdd(thread, receiver, key, JSHandle<JSTaggedValue>(thread, value),
996 PropertyAttributes::Default());
997
998 return true;
999 }
1000 if (holder.IsJSProxy()) {
1001 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1002 return JSProxy::SetProperty(thread, JSHandle<JSProxy>(thread, holder), JSHandle<JSTaggedValue>(thread, key),
1003 JSHandle<JSTaggedValue>(thread, value),
1004 JSHandle<JSTaggedValue>(thread, receiver), mayThrow);
1005 }
1006 onPrototype = true;
1007 }
1008 }
1009
SetGlobalOwnProperty(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,bool mayThrow)1010 bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
1011 JSTaggedValue value, bool mayThrow)
1012 {
1013 INTERPRETER_TRACE(thread, SetGlobalOwnProperty);
1014 uint32_t index = 0;
1015 if (JSTaggedValue::ToElementIndex(key, &index)) {
1016 return SetElement(thread, receiver, index, value, mayThrow);
1017 }
1018
1019 JSObject *obj = JSObject::Cast(receiver);
1020 GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
1021 PropertyAttributes attr = PropertyAttributes::Default();
1022 if (UNLIKELY(dict->GetLength() == 0)) {
1023 JSHandle<JSTaggedValue> keyHandle(thread, key);
1024 JSHandle<JSTaggedValue> valHandle(thread, value);
1025 JSHandle<JSObject> objHandle(thread, obj);
1026 JSHandle<GlobalDictionary> dictHandle(GlobalDictionary::Create(thread));
1027
1028 // Add PropertyBox to global dictionary
1029 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1030 JSHandle<PropertyBox> boxHandle = factory->NewPropertyBox(valHandle);
1031 boxHandle->SetValue(thread, valHandle.GetTaggedValue());
1032 PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
1033 attr.SetBoxType(boxType);
1034
1035 JSHandle<GlobalDictionary> properties =
1036 GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle<JSTaggedValue>(boxHandle), attr);
1037 objHandle->SetProperties(thread, properties);
1038 return true;
1039 }
1040
1041 int entry = dict->FindEntry(key);
1042 if (entry != -1) {
1043 attr = dict->GetAttributes(entry);
1044 JSTaggedValue val = dict->GetValue(entry);
1045 if (!attr.IsAccessor()) {
1046 if (attr.IsWritable()) {
1047 // globalobj have no internal accessor
1048 JSHandle<GlobalDictionary> dictHandle(thread, dict);
1049 GlobalDictionary::InvalidatePropertyBox(thread, dictHandle, entry, attr);
1050 return true;
1051 }
1052 }
1053
1054 // Accessor
1055 JSTaggedValue setter = AccessorData::Cast(val.GetHeapObject())->GetSetter();
1056 if (setter.IsUndefined()) {
1057 if (mayThrow) {
1058 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property when setter is undefined", false);
1059 }
1060 return false;
1061 }
1062
1063 JSHandle<JSTaggedValue> objHandle(thread, receiver);
1064 JSHandle<JSTaggedValue> setFunc(thread, setter);
1065 InternalCallParams *arguments = thread->GetInternalCallParams();
1066 arguments->MakeArgv(value);
1067 JSFunction::Call(thread, setFunc, objHandle, 1, arguments->GetArgv());
1068 // 10. ReturnIfAbrupt(setterResult).
1069 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1070 return true;
1071 }
1072
1073 JSHandle<JSTaggedValue> keyHandle(thread, key);
1074 JSHandle<JSTaggedValue> valHandle(thread, value);
1075 JSHandle<JSObject> objHandle(thread, obj);
1076 JSHandle<GlobalDictionary> dictHandle(thread, dict);
1077
1078 // Add PropertyBox to global dictionary
1079 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1080 JSHandle<PropertyBox> boxHandle = factory->NewPropertyBox(keyHandle);
1081 boxHandle->SetValue(thread, valHandle.GetTaggedValue());
1082 PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
1083 attr.SetBoxType(boxType);
1084
1085 JSHandle<GlobalDictionary> properties =
1086 GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle<JSTaggedValue>(boxHandle), attr);
1087 objHandle->SetProperties(thread, properties);
1088 return true;
1089 }
1090
1091 // set property that is not accessor and is writable
SetOwnPropertyByName(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value)1092 void FastRuntimeStub::SetOwnPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
1093 JSTaggedValue value)
1094 {
1095 INTERPRETER_TRACE(thread, SetOwnPropertyByName);
1096 TaggedArray *properties = TaggedArray::Cast(JSObject::Cast(receiver)->GetProperties().GetHeapObject());
1097 PropertyAttributes attr;
1098 uint32_t indexOrEntry;
1099 JSTaggedValue val = FindOwnProperty(thread, JSObject::Cast(receiver), properties, key, &attr, &indexOrEntry);
1100 if (!val.IsHole()) {
1101 ASSERT(!attr.IsAccessor() && attr.IsWritable());
1102 if (!properties->IsDictionaryMode()) {
1103 Representation representation = PropertyAttributes::UpdateRepresentation(attr.GetRepresentation(), value);
1104 if (attr.GetRepresentation() != representation) {
1105 attr.SetRepresentation(representation);
1106 }
1107
1108 JSObject::Cast(receiver)->GetJSHClass()->UpdatePropertyMetaData(thread, key, attr);
1109
1110 if (attr.IsInlinedProps()) {
1111 JSObject::Cast(receiver)->SetPropertyInlinedProps(thread, indexOrEntry, value);
1112 } else {
1113 properties->Set(thread, indexOrEntry, value);
1114 }
1115 return;
1116 }
1117
1118 NameDictionary::Cast(properties)->UpdateValueAndAttributes(thread, indexOrEntry, value, attr);
1119 return;
1120 }
1121 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1122
1123 ObjectOperator::FastAdd(thread, receiver, key, JSHandle<JSTaggedValue>(thread, value),
1124 PropertyAttributes::Default());
1125 }
1126
1127 // set element that is not accessor and is writable
SetOwnElement(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value)1128 bool FastRuntimeStub::SetOwnElement(JSThread *thread, JSTaggedValue receiver, uint32_t index, JSTaggedValue value)
1129 {
1130 INTERPRETER_TRACE(thread, SetOwnElement);
1131 PropertyAttributes attr;
1132 uint32_t indexOrEntry;
1133 TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(receiver)->GetElements().GetHeapObject());
1134 bool isDict = elements->IsDictionaryMode();
1135 [[maybe_unused]] JSTaggedValue val = FindOwnElement(elements, index, isDict, &attr, &indexOrEntry);
1136 if (!val.IsHole()) {
1137 ASSERT(!attr.IsAccessor() && attr.IsWritable());
1138 if (!isDict) {
1139 elements->Set(thread, indexOrEntry, value);
1140 JSObject::Cast(receiver)->GetJSHClass()->UpdateRepresentation(value);
1141 return true;
1142 }
1143 NumberDictionary::Cast(elements)->UpdateValueAndAttributes(thread, indexOrEntry, value, attr);
1144 return true;
1145 }
1146
1147 return JSObject::AddElementInternal(thread, JSHandle<JSObject>(thread, receiver), index,
1148 JSHandle<JSTaggedValue>(thread, value), PropertyAttributes::Default());
1149 }
1150
FastSetProperty(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key,JSTaggedValue value,bool mayThrow)1151 bool FastRuntimeStub::FastSetProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value,
1152 bool mayThrow)
1153 {
1154 INTERPRETER_TRACE(thread, FastSetProperty);
1155 if (receiver.IsJSObject() && !receiver.IsTypedArray() && (key.IsStringOrSymbol())) {
1156 uint32_t index = 0;
1157 if (UNLIKELY(JSTaggedValue::ToElementIndex(key, &index))) {
1158 if (!FastRuntimeStub::IsSpecialIndexedObjForSet(receiver)) {
1159 return FastRuntimeStub::SetElement(thread, receiver, index, value, true);
1160 }
1161 return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
1162 JSHandle<JSTaggedValue>(thread, key),
1163 JSHandle<JSTaggedValue>(thread, value), mayThrow);
1164 }
1165 if (key.IsString()) {
1166 key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
1167 }
1168 return FastRuntimeStub::SetPropertyByName(thread, receiver, key, value, mayThrow);
1169 }
1170 return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
1171 JSHandle<JSTaggedValue>(thread, key), JSHandle<JSTaggedValue>(thread, value),
1172 mayThrow);
1173 }
1174
FastGetProperty(JSThread * thread,JSTaggedValue receiver,JSTaggedValue key)1175 JSTaggedValue FastRuntimeStub::FastGetProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
1176 {
1177 INTERPRETER_TRACE(thread, FastGetProperty);
1178 JSTaggedValue result;
1179 if (receiver.IsJSObject() && !receiver.IsTypedArray() && (key.IsStringOrSymbol())) {
1180 uint32_t index = 0;
1181 if (UNLIKELY(JSTaggedValue::ToElementIndex(key, &index))) {
1182 if (FastRuntimeStub::IsSpecialIndexedObjForSet(receiver)) {
1183 result = JSTaggedValue::Hole();
1184 } else {
1185 result = FastRuntimeStub::GetElement(receiver, index);
1186 }
1187 } else {
1188 if (key.IsString()) {
1189 key = JSTaggedValue(
1190 thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
1191 }
1192 result = FastRuntimeStub::GetPropertyByName(thread, receiver, key);
1193 }
1194 }
1195 if (!result.IsHole()) {
1196 if (UNLIKELY(result.IsAccessor())) {
1197 return JSObject::CallGetter(thread, AccessorData::Cast(result.GetHeapObject()),
1198 JSHandle<JSTaggedValue>(thread, receiver));
1199 }
1200 return result;
1201 }
1202 return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
1203 JSHandle<JSTaggedValue>(thread, key))
1204 .GetValue()
1205 .GetTaggedValue();
1206 }
1207
FindOwnProperty(JSThread * thread,JSObject * obj,TaggedArray * properties,JSTaggedValue key,PropertyAttributes * attr,uint32_t * indexOrEntry)1208 JSTaggedValue FastRuntimeStub::FindOwnProperty(JSThread *thread, JSObject *obj, TaggedArray *properties,
1209 JSTaggedValue key, PropertyAttributes *attr, uint32_t *indexOrEntry)
1210 {
1211 INTERPRETER_TRACE(thread, FindOwnProperty);
1212 if (!properties->IsDictionaryMode()) {
1213 JSHClass *cls = obj->GetJSHClass();
1214 JSTaggedValue attrs = cls->GetLayout();
1215 if (!attrs.IsNull()) {
1216 LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetHeapObject());
1217 int propNumber = cls->NumberOfProps();
1218 int entry = layoutInfo->FindElementWithCache(thread, cls, key, propNumber);
1219 if (entry != -1) {
1220 *attr = layoutInfo->GetAttr(entry);
1221 ASSERT(entry == static_cast<int>(attr->GetOffset()));
1222 *indexOrEntry = entry;
1223 if (attr->IsInlinedProps()) {
1224 return obj->GetPropertyInlinedProps(entry);
1225 }
1226 *indexOrEntry -= cls->GetInlinedProperties();
1227 return properties->Get(*indexOrEntry);
1228 }
1229 }
1230 return JSTaggedValue::Hole(); // properties == empty properties will return here.
1231 }
1232
1233 if (obj->IsJSGlobalObject()) {
1234 GlobalDictionary *dict = GlobalDictionary::Cast(properties);
1235 int entry = dict->FindEntry(key);
1236 if (entry != -1) {
1237 *indexOrEntry = entry;
1238 *attr = dict->GetAttributes(entry);
1239 return dict->GetValue(entry);
1240 }
1241 return JSTaggedValue::Hole();
1242 }
1243
1244 NameDictionary *dict = NameDictionary::Cast(properties);
1245 int entry = dict->FindEntry(key);
1246 if (entry != -1) {
1247 *indexOrEntry = entry;
1248 *attr = dict->GetAttributes(entry);
1249 return dict->GetValue(entry);
1250 }
1251
1252 return JSTaggedValue::Hole();
1253 }
1254
FindOwnElement(TaggedArray * elements,uint32_t index,bool isDict,PropertyAttributes * attr,uint32_t * indexOrEntry)1255 JSTaggedValue FastRuntimeStub::FindOwnElement(TaggedArray *elements, uint32_t index, bool isDict,
1256 PropertyAttributes *attr, uint32_t *indexOrEntry)
1257 {
1258 if (!isDict) {
1259 if (elements->GetLength() <= index) {
1260 return JSTaggedValue::Hole();
1261 }
1262
1263 JSTaggedValue value = elements->Get(index);
1264 if (!value.IsHole()) {
1265 *attr = PropertyAttributes::Default();
1266 *indexOrEntry = index;
1267 return value;
1268 }
1269 } else {
1270 NumberDictionary *dict = NumberDictionary::Cast(elements);
1271 int entry = dict->FindEntry(JSTaggedValue(static_cast<int>(index)));
1272 if (entry != -1) {
1273 *indexOrEntry = entry;
1274 *attr = dict->GetAttributes(entry);
1275 return dict->GetValue(entry);
1276 }
1277 }
1278 return JSTaggedValue::Hole();
1279 }
1280
FindOwnProperty(JSThread * thread,JSObject * obj,JSTaggedValue key)1281 JSTaggedValue FastRuntimeStub::FindOwnProperty(JSThread *thread, JSObject *obj, JSTaggedValue key)
1282 {
1283 INTERPRETER_TRACE(thread, FindOwnProperty);
1284 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetHeapObject());
1285 if (!array->IsDictionaryMode()) {
1286 JSHClass *cls = obj->GetJSHClass();
1287 JSTaggedValue attrs = cls->GetLayout();
1288 if (!attrs.IsNull()) {
1289 LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetHeapObject());
1290 int propsNumber = cls->NumberOfProps();
1291 int entry = layoutInfo->FindElementWithCache(thread, cls, key, propsNumber);
1292 if (entry != -1) {
1293 PropertyAttributes attr(layoutInfo->GetAttr(entry));
1294 ASSERT(static_cast<int>(attr.GetOffset()) == entry);
1295 return attr.IsInlinedProps() ? obj->GetPropertyInlinedProps(entry)
1296 : array->Get(entry - cls->GetInlinedProperties());
1297 }
1298 }
1299 return JSTaggedValue::Hole(); // array == empty array will return here.
1300 }
1301
1302 if (obj->IsJSGlobalObject()) {
1303 GlobalDictionary *dict = GlobalDictionary::Cast(array);
1304 int entry = dict->FindEntry(key);
1305 if (entry != -1) {
1306 return dict->GetValue(entry);
1307 }
1308 return JSTaggedValue::Hole();
1309 }
1310
1311 NameDictionary *dict = NameDictionary::Cast(array);
1312 int entry = dict->FindEntry(key);
1313 if (entry != -1) {
1314 return dict->GetValue(entry);
1315 }
1316
1317 return JSTaggedValue::Hole();
1318 }
1319
FindOwnElement(JSObject * obj,uint32_t index)1320 JSTaggedValue FastRuntimeStub::FindOwnElement(JSObject *obj, uint32_t index)
1321 {
1322 TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(obj)->GetElements().GetHeapObject());
1323
1324 if (!elements->IsDictionaryMode()) {
1325 if (elements->GetLength() <= index) {
1326 return JSTaggedValue::Hole();
1327 }
1328
1329 JSTaggedValue value = elements->Get(index);
1330 if (!value.IsHole()) {
1331 return value;
1332 }
1333 } else {
1334 NumberDictionary *dict = NumberDictionary::Cast(elements);
1335 int entry = dict->FindEntry(JSTaggedValue(static_cast<int>(index)));
1336 if (entry != -1) {
1337 return dict->GetValue(entry);
1338 }
1339 }
1340 return JSTaggedValue::Hole();
1341 }
1342
HasOwnProperty(JSThread * thread,JSObject * obj,JSTaggedValue key)1343 JSTaggedValue FastRuntimeStub::HasOwnProperty(JSThread *thread, JSObject *obj, JSTaggedValue key)
1344 {
1345 INTERPRETER_TRACE(thread, HasOwnProperty);
1346 uint32_t index = 0;
1347 if (UNLIKELY(JSTaggedValue::ToElementIndex(key, &index))) {
1348 return FastRuntimeStub::FindOwnElement(obj, index);
1349 }
1350
1351 return FastRuntimeStub::FindOwnProperty(thread, obj, key);
1352 }
1353
GetContainerProperty(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSType jsType)1354 JSTaggedValue FastRuntimeStub::GetContainerProperty(JSThread *thread, JSTaggedValue receiver, uint32_t index,
1355 JSType jsType)
1356 {
1357 JSTaggedValue res = JSTaggedValue::Undefined();
1358 switch (jsType) {
1359 case JSType::JS_API_ARRAY_LIST:
1360 res = JSAPIArrayList::Cast(receiver.GetTaggedObject())->Get(thread, index);
1361 break;
1362 default:
1363 break;
1364 }
1365 return res;
1366 }
1367
SetContainerProperty(JSThread * thread,JSTaggedValue receiver,uint32_t index,JSTaggedValue value,JSType jsType)1368 JSTaggedValue FastRuntimeStub::SetContainerProperty(JSThread *thread, JSTaggedValue receiver, uint32_t index,
1369 JSTaggedValue value, JSType jsType)
1370 {
1371 JSTaggedValue res = JSTaggedValue::Undefined();
1372 switch (jsType) {
1373 case JSType::JS_API_ARRAY_LIST:
1374 res = JSAPIArrayList::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
1375 break;
1376 default:
1377 break;
1378 }
1379 return res;
1380 }
1381
NewThisObject(JSThread * thread,JSTaggedValue ctor,JSTaggedValue newTarget,InterpretedFrame * state)1382 JSTaggedValue FastRuntimeStub::NewThisObject(JSThread *thread, JSTaggedValue ctor, JSTaggedValue newTarget,
1383 InterpretedFrame *state)
1384 {
1385 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1386 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1387
1388 JSHandle<JSFunction> ctorHandle(thread, ctor);
1389 JSHandle<JSTaggedValue> newTargetHandle(thread, newTarget);
1390 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctorHandle, newTargetHandle);
1391 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
1392
1393 state->function = ctorHandle.GetTaggedValue();
1394 state->constpool = ctorHandle->GetConstantPool();
1395 state->profileTypeInfo = ctorHandle->GetProfileTypeInfo();
1396 state->env = ctorHandle->GetLexicalEnv();
1397
1398 return obj.GetTaggedValue();
1399 }
1400 } // namespace panda::ecmascript
1401 #endif // ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
1402