• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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