2021-09-04 08:06:49 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
#ifndef ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
|
|
|
|
#define ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
|
2021-09-04 08:06:49 +00:00
|
|
|
|
|
|
|
#include "ecmascript/interpreter/fast_runtime_stub.h"
|
|
|
|
|
|
|
|
#include "ecmascript/global_dictionary-inl.h"
|
|
|
|
#include "ecmascript/global_env.h"
|
2022-04-06 11:22:08 +00:00
|
|
|
#include "ecmascript/interpreter/interpreter.h"
|
2022-07-23 07:52:48 +00:00
|
|
|
#include "ecmascript/js_api/js_api_arraylist.h"
|
|
|
|
#include "ecmascript/js_api/js_api_deque.h"
|
|
|
|
#include "ecmascript/js_api/js_api_linked_list.h"
|
|
|
|
#include "ecmascript/js_api/js_api_list.h"
|
|
|
|
#include "ecmascript/js_api/js_api_plain_array.h"
|
|
|
|
#include "ecmascript/js_api/js_api_queue.h"
|
|
|
|
#include "ecmascript/js_api/js_api_stack.h"
|
|
|
|
#include "ecmascript/js_api/js_api_vector.h"
|
2021-09-04 08:06:49 +00:00
|
|
|
#include "ecmascript/js_function.h"
|
|
|
|
#include "ecmascript/js_hclass-inl.h"
|
|
|
|
#include "ecmascript/js_proxy.h"
|
|
|
|
#include "ecmascript/js_tagged_value-inl.h"
|
|
|
|
#include "ecmascript/js_typed_array.h"
|
|
|
|
#include "ecmascript/object_factory-inl.h"
|
2021-09-07 14:24:16 +00:00
|
|
|
#include "ecmascript/runtime_call_id.h"
|
2021-09-04 08:06:49 +00:00
|
|
|
#include "ecmascript/tagged_dictionary.h"
|
|
|
|
|
|
|
|
namespace panda::ecmascript {
|
2022-05-10 11:18:45 +00:00
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
|
|
|
#define CHECK_IS_ON_PROTOTYPE_CHAIN(receiver, holder) \
|
|
|
|
if (UNLIKELY((receiver) != (holder))) { \
|
|
|
|
return JSTaggedValue::Hole(); \
|
|
|
|
}
|
|
|
|
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::FastMul(JSTaggedValue left, JSTaggedValue right)
|
|
|
|
{
|
|
|
|
if (left.IsNumber() && right.IsNumber()) {
|
|
|
|
return JSTaggedValue(left.GetNumber() * right.GetNumber());
|
|
|
|
}
|
|
|
|
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastDiv(JSTaggedValue left, JSTaggedValue right)
|
|
|
|
{
|
|
|
|
if (left.IsNumber() && right.IsNumber()) {
|
|
|
|
double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
|
|
|
|
double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
|
|
|
|
if (UNLIKELY(dRight == 0.0)) {
|
|
|
|
if (dLeft == 0.0 || std::isnan(dLeft)) {
|
|
|
|
return JSTaggedValue(base::NAN_VALUE);
|
|
|
|
}
|
|
|
|
uint64_t flagBit = ((bit_cast<uint64_t>(dLeft)) ^ (bit_cast<uint64_t>(dRight))) & base::DOUBLE_SIGN_MASK;
|
|
|
|
return JSTaggedValue(bit_cast<double>(flagBit ^ (bit_cast<uint64_t>(base::POSITIVE_INFINITY))));
|
|
|
|
}
|
|
|
|
return JSTaggedValue(dLeft / dRight);
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastMod(JSTaggedValue left, JSTaggedValue right)
|
|
|
|
{
|
|
|
|
if (right.IsInt() && left.IsInt()) {
|
|
|
|
int iRight = right.GetInt();
|
|
|
|
int iLeft = left.GetInt();
|
|
|
|
if (iRight > 0 && iLeft > 0) {
|
|
|
|
return JSTaggedValue(iLeft % iRight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (left.IsNumber() && right.IsNumber()) {
|
|
|
|
double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
|
|
|
|
double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
|
|
|
|
if (dRight == 0.0 || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
|
|
|
|
return JSTaggedValue(base::NAN_VALUE);
|
|
|
|
}
|
|
|
|
if (dLeft == 0.0 || std::isinf(dRight)) {
|
|
|
|
return JSTaggedValue(dLeft);
|
|
|
|
}
|
|
|
|
return JSTaggedValue(std::fmod(dLeft, dRight));
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastEqual(JSTaggedValue left, JSTaggedValue right)
|
|
|
|
{
|
|
|
|
if (left == right) {
|
|
|
|
if (UNLIKELY(left.IsDouble())) {
|
|
|
|
return JSTaggedValue(!std::isnan(left.GetDouble()));
|
|
|
|
}
|
|
|
|
return JSTaggedValue::True();
|
|
|
|
}
|
|
|
|
if (left.IsNumber()) {
|
|
|
|
if (left.IsInt() && right.IsInt()) {
|
|
|
|
return JSTaggedValue::False();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (right.IsUndefinedOrNull()) {
|
|
|
|
if (left.IsHeapObject()) {
|
|
|
|
return JSTaggedValue::False();
|
|
|
|
}
|
|
|
|
if (left.IsUndefinedOrNull()) {
|
|
|
|
return JSTaggedValue::True();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (left.IsBoolean()) {
|
|
|
|
if (right.IsSpecial()) {
|
|
|
|
return JSTaggedValue::False();
|
|
|
|
}
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
if (left.IsBigInt() && right.IsBigInt()) {
|
|
|
|
return JSTaggedValue(BigInt::Equal(left, right));
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::FastStrictEqual(JSTaggedValue left, JSTaggedValue right)
|
|
|
|
{
|
|
|
|
if (left.IsNumber()) {
|
|
|
|
if (right.IsNumber()) {
|
|
|
|
double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
|
|
|
|
double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
|
|
|
|
return JSTaggedValue::StrictNumberEquals(dLeft, dRight);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (right.IsNumber()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (left == right) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (left.IsString() && right.IsString()) {
|
|
|
|
return EcmaString::StringsAreEqual(static_cast<EcmaString *>(left.GetTaggedObject()),
|
|
|
|
static_cast<EcmaString *>(right.GetTaggedObject()));
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
if (left.IsBigInt()) {
|
|
|
|
if (right.IsBigInt()) {
|
|
|
|
return BigInt::Equal(left, right);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (right.IsBigInt()) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::IsSpecialIndexedObj(JSType jsType)
|
|
|
|
{
|
|
|
|
return jsType > JSType::JS_ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::IsSpecialReceiverObj(JSType jsType)
|
|
|
|
{
|
|
|
|
return jsType > JSType::JS_PRIMITIVE_REF;
|
|
|
|
}
|
|
|
|
|
2022-01-04 11:30:40 +00:00
|
|
|
bool FastRuntimeStub::IsSpecialContainer(JSType jsType)
|
|
|
|
{
|
2022-03-05 02:35:02 +00:00
|
|
|
return jsType >= JSType::JS_API_ARRAY_LIST && jsType <= JSType::JS_API_QUEUE;
|
2022-01-04 11:30:40 +00:00
|
|
|
}
|
|
|
|
|
2021-09-04 08:06:49 +00:00
|
|
|
int32_t FastRuntimeStub::TryToElementsIndex(JSTaggedValue key)
|
|
|
|
{
|
|
|
|
if (LIKELY(key.IsInt())) {
|
|
|
|
return key.GetInt();
|
|
|
|
}
|
|
|
|
if (key.IsString()) {
|
|
|
|
uint32_t index = 0;
|
|
|
|
if (JSTaggedValue::StringToElementIndex(key, &index)) {
|
|
|
|
return static_cast<int32_t>(index);
|
|
|
|
}
|
|
|
|
} else if (key.IsDouble()) {
|
|
|
|
double number = key.GetDouble();
|
|
|
|
auto integer = static_cast<int32_t>(number);
|
|
|
|
if (number == integer) {
|
|
|
|
return integer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::CallGetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, CallGetter);
|
2021-09-04 08:06:49 +00:00
|
|
|
// Accessor
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
AccessorData *accessor = AccessorData::Cast(value.GetTaggedObject());
|
|
|
|
if (UNLIKELY(accessor->IsInternal())) {
|
|
|
|
JSHandle<JSObject> objHandle(thread, holder);
|
|
|
|
return accessor->CallInternalGet(thread, objHandle);
|
|
|
|
}
|
|
|
|
JSHandle<JSTaggedValue> objHandle(thread, receiver);
|
|
|
|
return JSObject::CallGetter(thread, accessor, objHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::CallSetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value,
|
|
|
|
JSTaggedValue accessorValue)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, CallSetter);
|
2021-09-04 08:06:49 +00:00
|
|
|
// Accessor
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
JSHandle<JSTaggedValue> objHandle(thread, receiver);
|
|
|
|
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
|
|
|
|
|
|
|
auto accessor = AccessorData::Cast(accessorValue.GetTaggedObject());
|
|
|
|
bool success = JSObject::CallSetter(thread, *accessor, objHandle, valueHandle, true);
|
|
|
|
return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::ShouldCallSetter(JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue accessorValue,
|
|
|
|
PropertyAttributes attr)
|
|
|
|
{
|
|
|
|
if (!AccessorData::Cast(accessorValue.GetTaggedObject())->IsInternal()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (receiver != holder) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return attr.IsWritable();
|
|
|
|
}
|
|
|
|
|
2021-12-17 09:18:10 +00:00
|
|
|
PropertyAttributes FastRuntimeStub::AddPropertyByName(JSThread *thread, JSHandle<JSObject> objHandle,
|
|
|
|
JSHandle<JSTaggedValue> keyHandle,
|
|
|
|
JSHandle<JSTaggedValue> valueHandle,
|
|
|
|
PropertyAttributes attr)
|
2021-09-04 08:06:49 +00:00
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, AddPropertyByName);
|
2021-09-04 08:06:49 +00:00
|
|
|
|
|
|
|
if (objHandle->IsJSArray() && keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()) {
|
|
|
|
objHandle->GetJSHClass()->SetHasConstructor(true);
|
|
|
|
}
|
2021-12-17 09:18:10 +00:00
|
|
|
int32_t nextInlinedPropsIndex = objHandle->GetJSHClass()->GetNextInlinedPropsIndex();
|
|
|
|
if (nextInlinedPropsIndex >= 0) {
|
|
|
|
objHandle->SetPropertyInlinedProps(thread, nextInlinedPropsIndex, valueHandle.GetTaggedValue());
|
|
|
|
attr.SetOffset(nextInlinedPropsIndex);
|
2021-09-04 08:06:49 +00:00
|
|
|
attr.SetIsInlinedProps(true);
|
|
|
|
JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
|
2021-12-17 09:18:10 +00:00
|
|
|
return attr;
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSMutableHandle<TaggedArray> array(thread, objHandle->GetProperties());
|
2022-01-14 13:50:26 +00:00
|
|
|
uint32_t length = array->GetLength();
|
2021-09-04 08:06:49 +00:00
|
|
|
if (length == 0) {
|
|
|
|
length = JSObject::MIN_PROPERTIES_LENGTH;
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
|
|
array.Update(factory->NewTaggedArray(length).GetTaggedValue());
|
|
|
|
objHandle->SetProperties(thread, array.GetTaggedValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!array->IsDictionaryMode()) {
|
|
|
|
attr.SetIsInlinedProps(false);
|
|
|
|
|
2022-04-12 08:49:37 +00:00
|
|
|
uint32_t nonInlinedProps = static_cast<uint32_t>(objHandle->GetJSHClass()->GetNextNonInlinedPropsIndex());
|
2021-12-17 09:18:10 +00:00
|
|
|
ASSERT(length >= nonInlinedProps);
|
2021-09-04 08:06:49 +00:00
|
|
|
// if array is full, grow array or change to dictionary mode
|
2021-12-17 09:18:10 +00:00
|
|
|
if (length == nonInlinedProps) {
|
|
|
|
if (UNLIKELY(length == JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)) {
|
2021-09-04 08:06:49 +00:00
|
|
|
// change to dictionary and add one.
|
|
|
|
JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread, objHandle));
|
2021-12-17 09:18:10 +00:00
|
|
|
JSHandle<NameDictionary> newDict =
|
|
|
|
NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
|
|
|
|
objHandle->SetProperties(thread, newDict);
|
2021-09-04 08:06:49 +00:00
|
|
|
// index is not essential when fastMode is false;
|
2021-12-17 09:18:10 +00:00
|
|
|
return attr;
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
// Grow properties array size
|
2022-01-14 13:50:26 +00:00
|
|
|
uint32_t capacity = JSObject::ComputePropertyCapacity(length);
|
2021-09-04 08:06:49 +00:00
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
|
|
array.Update(factory->CopyArray(array, length, capacity).GetTaggedValue());
|
|
|
|
objHandle->SetProperties(thread, array.GetTaggedValue());
|
|
|
|
}
|
|
|
|
|
2021-12-17 09:18:10 +00:00
|
|
|
attr.SetOffset(nonInlinedProps + objHandle->GetJSHClass()->GetInlinedProperties());
|
2021-09-04 08:06:49 +00:00
|
|
|
JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
|
2021-12-17 09:18:10 +00:00
|
|
|
array->Set(thread, nonInlinedProps, valueHandle.GetTaggedValue());
|
2021-09-04 08:06:49 +00:00
|
|
|
} else {
|
|
|
|
JSHandle<NameDictionary> dictHandle(array);
|
2021-12-17 09:18:10 +00:00
|
|
|
JSHandle<NameDictionary> newDict =
|
|
|
|
NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr);
|
|
|
|
objHandle->SetProperties(thread, newDict);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
2021-12-17 09:18:10 +00:00
|
|
|
return attr;
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::AddPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, AddPropertyByIndex);
|
2021-09-04 08:06:49 +00:00
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success = JSObject::AddElementInternal(thread, JSHandle<JSObject>(thread, receiver), index,
|
|
|
|
JSHandle<JSTaggedValue>(thread, value), PropertyAttributes::Default());
|
|
|
|
return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::GetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, GetPropertyByIndex);
|
2021-09-04 08:06:49 +00:00
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
JSTaggedValue holder = receiver;
|
|
|
|
do {
|
|
|
|
auto *hclass = holder.GetTaggedObject()->GetClass();
|
|
|
|
JSType jsType = hclass->GetObjectType();
|
|
|
|
if (IsSpecialIndexedObj(jsType)) {
|
2022-05-10 11:18:45 +00:00
|
|
|
if (IsFastTypeArray(jsType)) {
|
|
|
|
return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, jsType);
|
|
|
|
}
|
2022-01-04 11:30:40 +00:00
|
|
|
if (IsSpecialContainer(jsType)) {
|
|
|
|
return GetContainerProperty(thread, holder, index, jsType);
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(holder)->GetElements().GetTaggedObject());
|
|
|
|
|
|
|
|
if (!hclass->IsDictionaryElement()) {
|
|
|
|
ASSERT(!elements->IsDictionaryMode());
|
|
|
|
if (index < elements->GetLength()) {
|
|
|
|
JSTaggedValue value = elements->Get(index);
|
|
|
|
if (!value.IsHole()) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NumberDictionary *dict = NumberDictionary::Cast(elements);
|
|
|
|
int entry = dict->FindEntry(JSTaggedValue(static_cast<int>(index)));
|
|
|
|
if (entry != -1) {
|
|
|
|
auto attr = dict->GetAttributes(entry);
|
|
|
|
auto value = dict->GetValue(entry);
|
|
|
|
if (UNLIKELY(attr.IsAccessor())) {
|
|
|
|
return CallGetter(thread, receiver, holder, value);
|
|
|
|
}
|
|
|
|
ASSERT(!value.IsAccessor());
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (UseOwn) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
|
|
|
|
} while (holder.IsHeapObject());
|
|
|
|
|
|
|
|
// not found
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::GetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, GetPropertyByValue);
|
2021-09-04 08:06:49 +00:00
|
|
|
if (UNLIKELY(!key.IsNumber() && !key.IsStringOrSymbol())) {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
// fast path
|
|
|
|
auto index = TryToElementsIndex(key);
|
|
|
|
if (LIKELY(index >= 0)) {
|
|
|
|
return GetPropertyByIndex<UseOwn>(thread, receiver, index);
|
|
|
|
}
|
|
|
|
if (!key.IsNumber()) {
|
|
|
|
if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
|
|
|
|
// update string stable
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
|
|
|
|
key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
|
|
|
|
// Maybe moved by GC
|
|
|
|
receiver = receiverHandler.GetTaggedValue();
|
|
|
|
}
|
|
|
|
return FastRuntimeStub::GetPropertyByName<UseOwn>(thread, receiver, key);
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::GetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
|
|
|
{
|
2021-09-07 14:24:16 +00:00
|
|
|
INTERPRETER_TRACE(thread, GetPropertyByName);
|
2021-09-04 08:06:49 +00:00
|
|
|
// no gc when return hole
|
|
|
|
ASSERT(key.IsStringOrSymbol());
|
|
|
|
JSTaggedValue holder = receiver;
|
|
|
|
do {
|
|
|
|
auto *hclass = holder.GetTaggedObject()->GetClass();
|
|
|
|
JSType jsType = hclass->GetObjectType();
|
|
|
|
if (IsSpecialIndexedObj(jsType)) {
|
2022-05-10 11:18:45 +00:00
|
|
|
if (IsFastTypeArray(jsType)) {
|
|
|
|
JSTaggedValue res = FastGetTypeArrayProperty(thread, receiver, holder, key, jsType);
|
|
|
|
if (res.IsNull()) {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
} else if (UNLIKELY(!res.IsHole())) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (LIKELY(!hclass->IsDictionaryMode())) {
|
|
|
|
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
|
|
|
|
|
2021-12-17 09:18:10 +00:00
|
|
|
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
|
2022-04-12 08:49:37 +00:00
|
|
|
uint32_t propsNumber = hclass->NumberOfProps();
|
2021-09-04 08:06:49 +00:00
|
|
|
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
|
|
|
|
if (entry != -1) {
|
|
|
|
PropertyAttributes attr(layoutInfo->GetAttr(entry));
|
|
|
|
ASSERT(static_cast<int>(attr.GetOffset()) == entry);
|
|
|
|
auto value = JSObject::Cast(holder)->GetProperty(hclass, attr);
|
|
|
|
if (UNLIKELY(attr.IsAccessor())) {
|
|
|
|
return CallGetter(thread, receiver, holder, value);
|
|
|
|
}
|
|
|
|
ASSERT(!value.IsAccessor());
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TaggedArray *array = TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject());
|
|
|
|
ASSERT(array->IsDictionaryMode());
|
|
|
|
NameDictionary *dict = NameDictionary::Cast(array);
|
|
|
|
int entry = dict->FindEntry(key);
|
|
|
|
if (entry != -1) {
|
|
|
|
auto value = dict->GetValue(entry);
|
|
|
|
auto attr = dict->GetAttributes(entry);
|
|
|
|
if (UNLIKELY(attr.IsAccessor())) {
|
|
|
|
return CallGetter(thread, receiver, holder, value);
|
|
|
|
}
|
|
|
|
ASSERT(!value.IsAccessor());
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (UseOwn) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
holder = hclass->GetPrototype();
|
|
|
|
} while (holder.IsHeapObject());
|
|
|
|
// not found
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, SetPropertyByName);
|
2021-09-04 08:06:49 +00:00
|
|
|
// property
|
|
|
|
JSTaggedValue holder = receiver;
|
|
|
|
do {
|
|
|
|
auto *hclass = holder.GetTaggedObject()->GetClass();
|
|
|
|
JSType jsType = hclass->GetObjectType();
|
|
|
|
if (IsSpecialIndexedObj(jsType)) {
|
2022-05-10 11:18:45 +00:00
|
|
|
if (IsFastTypeArray(jsType)) {
|
|
|
|
JSTaggedValue res = FastSetTypeArrayProperty(thread, receiver, holder, key, value, jsType);
|
|
|
|
if (res.IsNull()) {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
} else if (UNLIKELY(!res.IsHole())) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
} else if (IsSpecialContainer(jsType)) {
|
2022-01-04 11:30:40 +00:00
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", JSTaggedValue::Exception());
|
2022-05-10 11:18:45 +00:00
|
|
|
} else {
|
|
|
|
return JSTaggedValue::Hole();
|
2022-01-04 11:30:40 +00:00
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
// UpdateRepresentation
|
|
|
|
if (LIKELY(!hclass->IsDictionaryMode())) {
|
|
|
|
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
|
|
|
|
|
2021-12-17 09:18:10 +00:00
|
|
|
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
|
2021-09-04 08:06:49 +00:00
|
|
|
|
2022-04-12 08:49:37 +00:00
|
|
|
uint32_t propsNumber = hclass->NumberOfProps();
|
2021-09-04 08:06:49 +00:00
|
|
|
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
|
|
|
|
if (entry != -1) {
|
|
|
|
PropertyAttributes attr(layoutInfo->GetAttr(entry));
|
|
|
|
ASSERT(static_cast<int>(attr.GetOffset()) == entry);
|
|
|
|
if (UNLIKELY(attr.IsAccessor())) {
|
|
|
|
auto accessor = JSObject::Cast(holder)->GetProperty(hclass, attr);
|
|
|
|
if (ShouldCallSetter(receiver, holder, accessor, attr)) {
|
|
|
|
return CallSetter(thread, receiver, value, accessor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (UNLIKELY(!attr.IsWritable())) {
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", JSTaggedValue::Exception());
|
|
|
|
}
|
|
|
|
if (UNLIKELY(holder != receiver)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value);
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TaggedArray *properties = TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject());
|
|
|
|
ASSERT(properties->IsDictionaryMode());
|
|
|
|
NameDictionary *dict = NameDictionary::Cast(properties);
|
|
|
|
int entry = dict->FindEntry(key);
|
|
|
|
if (entry != -1) {
|
|
|
|
auto attr = dict->GetAttributes(entry);
|
|
|
|
if (UNLIKELY(attr.IsAccessor())) {
|
|
|
|
auto accessor = dict->GetValue(entry);
|
|
|
|
if (ShouldCallSetter(receiver, holder, accessor, attr)) {
|
|
|
|
return CallSetter(thread, receiver, value, accessor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (UNLIKELY(!attr.IsWritable())) {
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set readonly property", JSTaggedValue::Exception());
|
|
|
|
}
|
|
|
|
if (UNLIKELY(holder != receiver)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dict->UpdateValue(thread, entry, value);
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (UseOwn) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
holder = hclass->GetPrototype();
|
|
|
|
} while (holder.IsHeapObject());
|
|
|
|
|
2021-12-17 09:18:10 +00:00
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
JSHandle<JSObject> objHandle(thread, receiver);
|
|
|
|
JSHandle<JSTaggedValue> keyHandle(thread, key);
|
|
|
|
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
|
|
|
|
|
|
|
if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
|
|
|
|
}
|
|
|
|
AddPropertyByName(thread, objHandle, keyHandle, valueHandle, PropertyAttributes::Default());
|
|
|
|
return JSTaggedValue::Undefined();
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::SetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, SetPropertyByIndex);
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue holder = receiver;
|
|
|
|
do {
|
|
|
|
auto *hclass = holder.GetTaggedObject()->GetClass();
|
|
|
|
JSType jsType = hclass->GetObjectType();
|
|
|
|
if (IsSpecialIndexedObj(jsType)) {
|
2022-05-10 11:18:45 +00:00
|
|
|
if (IsFastTypeArray(jsType)) {
|
|
|
|
return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, jsType);
|
|
|
|
}
|
2022-01-04 11:30:40 +00:00
|
|
|
if (IsSpecialContainer(jsType)) {
|
|
|
|
return SetContainerProperty(thread, holder, index, value, jsType);
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
TaggedArray *elements = TaggedArray::Cast(JSObject::Cast(holder)->GetElements().GetTaggedObject());
|
|
|
|
if (!hclass->IsDictionaryElement()) {
|
|
|
|
ASSERT(!elements->IsDictionaryMode());
|
|
|
|
if (UNLIKELY(holder != receiver)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (index < elements->GetLength()) {
|
|
|
|
if (!elements->Get(index).IsHole()) {
|
|
|
|
elements->Set(thread, index, value);
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
if (UseOwn) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
holder = JSObject::Cast(holder)->GetJSHClass()->GetPrototype();
|
|
|
|
} while (holder.IsHeapObject());
|
|
|
|
|
|
|
|
return AddPropertyByIndex(thread, receiver, index, value);
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseOwn>
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::SetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, SetPropertyByValue);
|
2021-09-04 08:06:49 +00:00
|
|
|
if (UNLIKELY(!key.IsNumber() && !key.IsStringOrSymbol())) {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
// fast path
|
|
|
|
auto index = TryToElementsIndex(key);
|
|
|
|
if (LIKELY(index >= 0)) {
|
|
|
|
return SetPropertyByIndex<UseOwn>(thread, receiver, index, value);
|
|
|
|
}
|
|
|
|
if (!key.IsNumber()) {
|
|
|
|
if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
|
|
|
|
// update string stable
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
|
|
|
|
JSHandle<JSTaggedValue> valueHandler(thread, value);
|
|
|
|
key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
|
|
|
|
// Maybe moved by GC
|
|
|
|
receiver = receiverHandler.GetTaggedValue();
|
|
|
|
value = valueHandler.GetTaggedValue();
|
|
|
|
}
|
|
|
|
return FastRuntimeStub::SetPropertyByName<UseOwn>(thread, receiver, key, value);
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
2022-02-17 05:00:20 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::GetGlobalOwnProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
2021-09-04 08:06:49 +00:00
|
|
|
{
|
|
|
|
JSObject *obj = JSObject::Cast(receiver);
|
|
|
|
TaggedArray *properties = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
|
|
|
|
GlobalDictionary *dict = GlobalDictionary::Cast(properties);
|
|
|
|
int entry = dict->FindEntry(key);
|
|
|
|
if (entry != -1) {
|
2022-02-17 05:00:20 +00:00
|
|
|
auto value = dict->GetValue(entry);
|
|
|
|
if (UNLIKELY(value.IsAccessor())) {
|
|
|
|
return CallGetter(thread, receiver, receiver, value);
|
|
|
|
}
|
|
|
|
ASSERT(!value.IsAccessor());
|
|
|
|
return value;
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
2022-02-16 03:05:56 +00:00
|
|
|
return JSTaggedValue::Hole();
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastTypeOf(JSThread *thread, JSTaggedValue obj)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastTypeOf);
|
2021-09-04 08:06:49 +00:00
|
|
|
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
|
|
|
switch (obj.GetRawData()) {
|
|
|
|
case JSTaggedValue::VALUE_TRUE:
|
|
|
|
case JSTaggedValue::VALUE_FALSE:
|
|
|
|
return globalConst->GetBooleanString();
|
|
|
|
case JSTaggedValue::VALUE_NULL:
|
|
|
|
return globalConst->GetObjectString();
|
|
|
|
case JSTaggedValue::VALUE_UNDEFINED:
|
|
|
|
return globalConst->GetUndefinedString();
|
|
|
|
default:
|
|
|
|
if (obj.IsHeapObject()) {
|
|
|
|
if (obj.IsString()) {
|
|
|
|
return globalConst->GetStringString();
|
|
|
|
}
|
|
|
|
if (obj.IsSymbol()) {
|
|
|
|
return globalConst->GetSymbolString();
|
|
|
|
}
|
|
|
|
if (obj.IsCallable()) {
|
|
|
|
return globalConst->GetFunctionString();
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
if (obj.IsBigInt()) {
|
|
|
|
return globalConst->GetBigIntString();
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
return globalConst->GetObjectString();
|
|
|
|
}
|
|
|
|
if (obj.IsNumber()) {
|
|
|
|
return globalConst->GetNumberString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return globalConst->GetUndefinedString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::FastSetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastSetPropertyByIndex);
|
2021-10-25 12:50:39 +00:00
|
|
|
JSTaggedValue result = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value);
|
2021-09-04 08:06:49 +00:00
|
|
|
if (!result.IsHole()) {
|
|
|
|
return result != JSTaggedValue::Exception();
|
|
|
|
}
|
|
|
|
return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver), index,
|
|
|
|
JSHandle<JSTaggedValue>(thread, value), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::FastSetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
|
|
|
|
JSTaggedValue value)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastSetPropertyByValue);
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue result = FastRuntimeStub::SetPropertyByValue(thread, receiver, key, value);
|
|
|
|
if (!result.IsHole()) {
|
|
|
|
return result != JSTaggedValue::Exception();
|
|
|
|
}
|
|
|
|
return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
|
|
|
|
JSHandle<JSTaggedValue>(thread, key), JSHandle<JSTaggedValue>(thread, value),
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// must not use for interpreter
|
|
|
|
JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastGetPropertyByName);
|
2021-09-04 08:06:49 +00:00
|
|
|
ASSERT(key.IsStringOrSymbol());
|
|
|
|
if (key.IsString() && !EcmaString::Cast(key.GetTaggedObject())->IsInternString()) {
|
|
|
|
JSHandle<JSTaggedValue> receiverHandler(thread, receiver);
|
|
|
|
key = JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(JSHandle<JSTaggedValue>(thread, key)));
|
|
|
|
// Maybe moved by GC
|
|
|
|
receiver = receiverHandler.GetTaggedValue();
|
|
|
|
}
|
2021-10-25 12:50:39 +00:00
|
|
|
JSTaggedValue result = FastRuntimeStub::GetPropertyByName(thread, receiver, key);
|
2021-09-04 08:06:49 +00:00
|
|
|
if (result.IsHole()) {
|
|
|
|
return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
|
|
|
|
JSHandle<JSTaggedValue>(thread, key))
|
|
|
|
.GetValue()
|
|
|
|
.GetTaggedValue();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastGetPropertyByValue);
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue result = FastRuntimeStub::GetPropertyByValue(thread, receiver, key);
|
|
|
|
if (result.IsHole()) {
|
|
|
|
return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver),
|
|
|
|
JSHandle<JSTaggedValue>(thread, key))
|
|
|
|
.GetValue()
|
|
|
|
.GetTaggedValue();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-07 14:24:16 +00:00
|
|
|
template<bool UseHole> // UseHole is only for Array::Sort() which requires Hole order
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, FastGetPropertyByIndex);
|
2021-10-25 12:50:39 +00:00
|
|
|
JSTaggedValue result = FastRuntimeStub::GetPropertyByIndex(thread, receiver, index);
|
2021-09-04 08:06:49 +00:00
|
|
|
if (result.IsHole() && !UseHole) {
|
|
|
|
return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(thread, receiver), index)
|
|
|
|
.GetValue()
|
|
|
|
.GetTaggedValue();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::NewLexicalEnvDyn(JSThread *thread, ObjectFactory *factory, uint16_t numVars)
|
|
|
|
{
|
2021-09-16 03:25:47 +00:00
|
|
|
INTERPRETER_TRACE(thread, NewLexicalEnvDyn);
|
2021-09-04 08:06:49 +00:00
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
LexicalEnv *newEnv = factory->InlineNewLexicalEnv(numVars);
|
|
|
|
if (UNLIKELY(newEnv == nullptr)) {
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
JSTaggedValue currentLexenv = thread->GetCurrentLexenv();
|
|
|
|
newEnv->SetParentEnv(thread, currentLexenv);
|
2022-02-26 07:55:01 +00:00
|
|
|
newEnv->SetScopeInfo(thread, JSTaggedValue::Hole());
|
2021-09-04 08:06:49 +00:00
|
|
|
return JSTaggedValue(newEnv);
|
|
|
|
}
|
|
|
|
|
2022-01-04 11:30:40 +00:00
|
|
|
JSTaggedValue FastRuntimeStub::GetContainerProperty(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
|
|
|
JSType jsType)
|
|
|
|
{
|
|
|
|
JSTaggedValue res = JSTaggedValue::Undefined();
|
|
|
|
switch (jsType) {
|
2022-02-17 09:00:31 +00:00
|
|
|
case JSType::JS_API_ARRAY_LIST:
|
|
|
|
res = JSAPIArrayList::Cast(receiver.GetTaggedObject())->Get(thread, index);
|
2022-01-04 11:30:40 +00:00
|
|
|
break;
|
2022-03-05 02:35:02 +00:00
|
|
|
case JSType::JS_API_QUEUE:
|
|
|
|
res = JSAPIQueue::Cast(receiver.GetTaggedObject())->Get(thread, index);
|
|
|
|
break;
|
2022-04-12 01:39:08 +00:00
|
|
|
case JSType::JS_API_PLAIN_ARRAY:
|
|
|
|
res = JSAPIPlainArray::Cast(receiver.GetTaggedObject())->Get(JSTaggedValue(index));
|
|
|
|
break;
|
2022-03-28 03:12:46 +00:00
|
|
|
case JSType::JS_API_DEQUE:
|
|
|
|
res = JSAPIDeque::Cast(receiver.GetTaggedObject())->Get(index);
|
|
|
|
break;
|
|
|
|
case JSType::JS_API_STACK:
|
|
|
|
res = JSAPIStack::Cast(receiver.GetTaggedObject())->Get(index);
|
|
|
|
break;
|
2022-05-23 01:49:27 +00:00
|
|
|
case JSType::JS_API_VECTOR: {
|
|
|
|
auto self = JSHandle<JSTaggedValue>(thread, receiver);
|
|
|
|
res = JSAPIVector::Get(thread, JSHandle<JSAPIVector>::Cast(self), index);
|
|
|
|
break;
|
|
|
|
}
|
2022-06-02 01:11:52 +00:00
|
|
|
case JSType::JS_API_LIST: {
|
|
|
|
res = JSAPIList::Cast(receiver.GetTaggedObject())->Get(index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JSType::JS_API_LINKED_LIST: {
|
|
|
|
res = JSAPILinkedList::Cast(receiver.GetTaggedObject())->Get(index);
|
|
|
|
break;
|
|
|
|
}
|
2022-01-04 11:30:40 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::SetContainerProperty(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
|
|
|
JSTaggedValue value, JSType jsType)
|
|
|
|
{
|
|
|
|
JSTaggedValue res = JSTaggedValue::Undefined();
|
|
|
|
switch (jsType) {
|
2022-02-17 09:00:31 +00:00
|
|
|
case JSType::JS_API_ARRAY_LIST:
|
|
|
|
res = JSAPIArrayList::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
|
2022-03-05 02:35:02 +00:00
|
|
|
break;
|
|
|
|
case JSType::JS_API_QUEUE:
|
|
|
|
res = JSAPIQueue::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
|
2022-03-28 03:12:46 +00:00
|
|
|
break;
|
2022-06-02 01:11:52 +00:00
|
|
|
case JSType::JS_API_PLAIN_ARRAY: {
|
|
|
|
JSHandle<JSAPIPlainArray> plainArray(thread, receiver);
|
|
|
|
res = JSAPIPlainArray::Set(thread, plainArray, index, value);
|
2022-04-12 01:39:08 +00:00
|
|
|
break;
|
2022-06-02 01:11:52 +00:00
|
|
|
}
|
2022-03-28 03:12:46 +00:00
|
|
|
case JSType::JS_API_DEQUE:
|
|
|
|
res = JSAPIDeque::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
|
|
|
|
break;
|
|
|
|
case JSType::JS_API_STACK:
|
|
|
|
res = JSAPIStack::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
|
2022-01-04 11:30:40 +00:00
|
|
|
break;
|
2022-05-23 01:49:27 +00:00
|
|
|
case JSType::JS_API_VECTOR:
|
|
|
|
res = JSAPIVector::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
|
|
|
|
break;
|
2022-06-02 01:11:52 +00:00
|
|
|
case JSType::JS_API_LIST: {
|
|
|
|
JSHandle<JSAPIList> singleList(thread, receiver);
|
|
|
|
res = JSAPIList::Set(thread, singleList, index, JSHandle<JSTaggedValue>(thread, value));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JSType::JS_API_LINKED_LIST: {
|
|
|
|
JSHandle<JSAPILinkedList> doubleList(thread, receiver);
|
|
|
|
res = JSAPILinkedList::Set(thread, doubleList, index, JSHandle<JSTaggedValue>(thread, value));
|
|
|
|
break;
|
|
|
|
}
|
2022-01-04 11:30:40 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2022-03-01 11:19:40 +00:00
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::NewThisObject(JSThread *thread, JSTaggedValue ctor, JSTaggedValue newTarget,
|
|
|
|
InterpretedFrame *state)
|
|
|
|
{
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
|
|
|
|
|
|
JSHandle<JSFunction> ctorHandle(thread, ctor);
|
|
|
|
JSHandle<JSTaggedValue> newTargetHandle(thread, newTarget);
|
|
|
|
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctorHandle, newTargetHandle);
|
|
|
|
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
|
|
|
|
|
|
|
state->function = ctorHandle.GetTaggedValue();
|
2022-08-23 01:56:32 +00:00
|
|
|
state->constpool = Method::Cast(ctorHandle->GetMethod().GetTaggedObject())->GetConstantPool();
|
2022-03-01 11:19:40 +00:00
|
|
|
state->profileTypeInfo = ctorHandle->GetProfileTypeInfo();
|
|
|
|
state->env = ctorHandle->GetLexicalEnv();
|
|
|
|
|
|
|
|
return obj.GetTaggedValue();
|
|
|
|
}
|
2022-04-06 12:00:22 +00:00
|
|
|
|
2022-05-10 11:18:45 +00:00
|
|
|
bool FastRuntimeStub::TryStringOrSymbolToIndex(JSTaggedValue key, uint32_t *output)
|
|
|
|
{
|
|
|
|
if (key.IsSymbol()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto strObj = static_cast<EcmaString *>(key.GetTaggedObject());
|
|
|
|
uint32_t len = strObj->GetLength();
|
|
|
|
if (UNLIKELY(len == 0 || len > MAX_INDEX_LEN)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (UNLIKELY(strObj->IsUtf16())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t c = strObj->GetDataUtf8()[0]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
|
|
uint64_t n = 0;
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
if (c == '0') {
|
|
|
|
if (len != 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*output = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = c - '0';
|
|
|
|
for (uint32_t i = 1; i < len; i++) {
|
|
|
|
c = strObj->GetDataUtf8()[i]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
// NOLINTNEXTLINE(readability-magic-numbers)
|
|
|
|
n = n * 10 + (c - '0'); // 10: decimal factor
|
|
|
|
} else if (c == '.') {
|
|
|
|
n = JSObject::MAX_ELEMENT_INDEX;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (n < JSObject::MAX_ELEMENT_INDEX) {
|
|
|
|
*output = n;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
*output = JSObject::MAX_ELEMENT_INDEX;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (c == '-') {
|
|
|
|
*output = JSObject::MAX_ELEMENT_INDEX;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FastRuntimeStub::IsFastTypeArray(JSType jsType)
|
|
|
|
{
|
2022-07-31 15:42:08 +00:00
|
|
|
return jsType >= JSType::JS_TYPED_ARRAY_FIRST && jsType <= JSType::JS_FLOAT64_ARRAY;
|
2022-05-10 11:18:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastGetTypeArrayProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
|
|
|
|
JSTaggedValue key, JSType jsType)
|
|
|
|
{
|
|
|
|
CHECK_IS_ON_PROTOTYPE_CHAIN(receiver, holder);
|
|
|
|
JSTaggedValue negativeZero = thread->GlobalConstants()->GetNegativeZeroString();
|
|
|
|
if (UNLIKELY(negativeZero == key)) {
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
uint32_t index = 0;
|
|
|
|
if (TryStringOrSymbolToIndex(key, &index)) {
|
|
|
|
if (UNLIKELY(index == JSObject::MAX_ELEMENT_INDEX)) {
|
|
|
|
return JSTaggedValue::Null();
|
|
|
|
}
|
|
|
|
return JSTypedArray::FastGetPropertyByIndex(thread, receiver, index, jsType);
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSTaggedValue FastRuntimeStub::FastSetTypeArrayProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
|
|
|
|
JSTaggedValue key, JSTaggedValue value, JSType jsType)
|
|
|
|
{
|
|
|
|
CHECK_IS_ON_PROTOTYPE_CHAIN(receiver, holder);
|
|
|
|
JSTaggedValue negativeZero = thread->GlobalConstants()->GetNegativeZeroString();
|
|
|
|
if (UNLIKELY(negativeZero == key)) {
|
|
|
|
if (value.IsECMAObject()) {
|
|
|
|
return JSTaggedValue::Null();
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
|
|
|
uint32_t index = 0;
|
|
|
|
if (TryStringOrSymbolToIndex(key, &index)) {
|
|
|
|
if (UNLIKELY(index == JSObject::MAX_ELEMENT_INDEX)) {
|
|
|
|
return JSTaggedValue::Null();
|
|
|
|
}
|
|
|
|
return JSTypedArray::FastSetPropertyByIndex(thread, receiver, index, value, jsType);
|
|
|
|
}
|
|
|
|
return JSTaggedValue::Hole();
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
} // namespace panda::ecmascript
|
2021-09-07 14:24:16 +00:00
|
|
|
#endif // ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
|