* 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.
*/
#include "ecmascript/builtins/builtins_object.h"
#include "ecmascript/builtins/builtins_map.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/object_fast_operator-inl.h"
namespace panda::ecmascript::builtins {
JSTaggedValue BuiltinsObject::ObjectConstructor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Constructor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto ecmaVm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
if (!newTarget->IsUndefined() && !(newTarget.GetTaggedValue() == constructor.GetTaggedValue())) {
JSHandle<JSObject> obj =
ecmaVm->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return obj.GetTaggedValue();
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
if (value->IsNull() || value->IsUndefined()) {
JSHandle<JSObject> obj = ecmaVm->GetFactory()->OrdinaryNewJSObjectCreate(env->GetObjectFunctionPrototype());
return obj.GetTaggedValue();
}
return JSTaggedValue::ToObject(thread, value).GetTaggedValue();
}
JSTaggedValue BuiltinsObject::AssignTaggedValue(JSThread *thread, const JSHandle<JSTaggedValue> &source,
const JSHandle<JSObject> &toAssign)
{
JSHandle<JSObject> from = JSTaggedValue::ToObject(thread, source);
JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(from));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
uint32_t keysLen = keys->GetLength();
for (uint32_t j = 0; j < keysLen; j++) {
PropertyDescriptor desc(thread);
key.Update(keys->Get(thread, j));
bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(from), key, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (success && desc.IsEnumerable()) {
JSTaggedValue value = desc.GetValue().GetTaggedValue();
if (value.IsUndefined() || JSHandle<JSTaggedValue>::Cast(from)->IsJSProxy()) {
value = ObjectFastOperator::FastGetPropertyByValue(thread, from.GetTaggedValue(),
key.GetTaggedValue());
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
ObjectFastOperator::FastSetPropertyByValue(thread, toAssign.GetTaggedValue(), key.GetTaggedValue(),
value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsObject::Assign(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Assign);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
uint32_t numArgs = argv->GetArgsNumber();
JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
JSHandle<JSObject> toAssign = JSTaggedValue::ToObject(thread, target);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
for (uint32_t i = 1; i < numArgs; i++) {
JSHandle<JSTaggedValue> source = GetCallArg(argv, i);
if (!source->IsNull() && !source->IsUndefined()) {
JSHandle<JSObject> from = JSTaggedValue::ToObject(thread, source);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(from));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t keysLen = keys->GetLength();
for (uint32_t j = 0; j < keysLen; j++) {
PropertyDescriptor desc(thread);
key.Update(keys->Get(thread, j));
bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(from), key, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (success && desc.IsEnumerable()) {
JSTaggedValue value = desc.GetValue().GetTaggedValue();
if (value.IsUndefined() || JSHandle<JSTaggedValue>::Cast(from)->IsJSProxy()) {
value = ObjectFastOperator::FastGetPropertyByValue(thread, from.GetTaggedValue(),
key.GetTaggedValue());
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
ObjectFastOperator::FastSetPropertyByValue(thread, toAssign.GetTaggedValue(), key.GetTaggedValue(),
value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
}
}
return toAssign.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::ObjectDefineProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &prop)
{
BUILTINS_API_TRACE(thread, Object, DefineProperties);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
if (!obj->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "is not an object", JSTaggedValue::Exception());
}
JSHandle<JSObject> props = JSTaggedValue::ToObject(thread, prop);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> handleKeys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(props));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t length = handleKeys->GetLength();
[[maybe_unused]] JSHandle<TaggedArray> descriptors =
factory->NewTaggedArray(2 * length);
std::vector<PropertyDescriptor> desArr;
for (uint32_t i = 0; i < length; i++) {
PropertyDescriptor propDesc(thread);
JSHandle<JSTaggedValue> handleKey(thread, handleKeys->Get(thread, i));
bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(props), handleKey, propDesc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (success && propDesc.IsEnumerable()) {
JSHandle<JSTaggedValue> descObj =
JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(props), handleKey).GetValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PropertyDescriptor desc(thread);
JSObject::ToPropertyDescriptor(thread, descObj, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
desc.SetKey(handleKey);
desArr.emplace_back(desc);
}
}
uint32_t desLength = desArr.size();
for (uint32_t i = 0; i < desLength; i++) {
JSHandle<JSTaggedValue> key = desArr[i].GetKey();
[[maybe_unused]] bool setSuccess =
JSTaggedValue::DefinePropertyOrThrow(thread, obj, key, desArr[i]);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PostHandleDefineProperty(thread, obj, key);
}
return obj.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::Create(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Create);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject() && !obj->IsNull()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Create: O is neither Object nor Null", JSTaggedValue::Exception());
}
if (obj->IsJSShared()) {
THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(CreateObjectWithSendableProto),
JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> properties = GetCallArg(argv, 1);
JSHandle<JSObject> objCreate = thread->GetEcmaVM()->GetFactory()->OrdinaryNewJSObjectCreate(obj);
if (!properties->IsUndefined()) {
return ObjectDefineProperties(thread, JSHandle<JSTaggedValue>::Cast(objCreate), properties);
}
return objCreate.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::DefineProperties(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, DefineProperties);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
return ObjectDefineProperties(thread, GetCallArg(argv, 0), GetCallArg(argv, 1));
}
JSTaggedValue BuiltinsObject::DefineProperty(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, DefineProperty);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "DefineProperty: O is not Object", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> prop = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, prop);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PropertyDescriptor desc(thread);
JSObject::ToPropertyDescriptor(thread, GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD), desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
[[maybe_unused]] bool success = JSTaggedValue::DefinePropertyOrThrow(thread, obj, key, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PostHandleDefineProperty(thread, obj, key);
return obj.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::Freeze(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Freeze);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject()) {
return obj.GetTaggedValue();
}
[[maybe_unused]] EcmaHandleScope handleScope(thread);
bool status = false;
if (obj->IsJSSharedObject() || obj->IsJSSharedFunction() || obj->IsJSSharedAsyncFunction()) {
status = JSObject::FreezeSharedObject(thread, JSHandle<JSObject>(obj));
} else if (obj->IsJSSharedArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(UpdateSendableAttributes), JSTaggedValue::Exception());
} else {
status = JSObject::SetIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::FROZEN);
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!status) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Freeze: freeze failed", JSTaggedValue::Exception());
}
return obj.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::GetOwnPropertyDescriptor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, GetOwnPropertyDescriptor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> func = GetCallArg(argv, 0);
JSHandle<JSObject> handle = JSTaggedValue::ToObject(thread, func);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> prop = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, prop);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PropertyDescriptor desc(thread);
JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(handle), key, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> res = JSObject::FromPropertyDescriptor(thread, desc);
return res.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::GetOwnPropertyDescriptors(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, GetOwnPropertyDescriptors);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> func = GetCallArg(argv, 0);
JSHandle<JSObject> handle = JSTaggedValue::ToObject(thread, func);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> ownKeys =
JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(handle));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> constructor(env->GetObjectFunction());
JSHandle<JSObject> descriptors = factory->NewJSObjectByConstructor(constructor);
uint32_t length = ownKeys->GetLength();
JSMutableHandle<JSTaggedValue> handleKey(thread, JSTaggedValue::Undefined());
for (uint32_t i = 0; i < length; ++i) {
handleKey.Update(ownKeys->Get(thread, i));
PropertyDescriptor desc(thread);
JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(handle), handleKey, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> descriptor = JSObject::FromPropertyDescriptor(thread, desc);
if (!descriptor->IsUndefined()) {
JSObject::CreateDataPropertyOrThrow(thread, descriptors, handleKey, descriptor);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
return descriptors.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &object,
const KeyType &type)
{
BUILTINS_API_TRACE(thread, Object, GetOwnPropertyKeys);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, object);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> handleKeys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(obj));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t length = handleKeys->GetLength();
JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
uint32_t copyLength = 0;
switch (type) {
case KeyType::STRING_TYPE: {
for (uint32_t i = 0; i < length; i++) {
JSTaggedValue key = handleKeys->Get(thread, i);
if (key.IsString()) {
nameList->Set(thread, copyLength, key);
copyLength++;
}
}
break;
}
case KeyType::SYMBOL_TYPE: {
for (uint32_t i = 0; i < length; i++) {
JSTaggedValue key = handleKeys->Get(thread, i);
if (key.IsSymbol()) {
nameList->Set(thread, copyLength, key);
copyLength++;
}
}
break;
}
default:
break;
}
JSHandle<TaggedArray> resultList = factory->CopyArray(nameList, length, copyLength);
JSHandle<JSArray> resultArray = JSArray::CreateArrayFromList(thread, resultList);
return resultArray.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::GetOwnPropertyNames(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, GetOwnPropertyNames);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
KeyType type = KeyType::STRING_TYPE;
return GetOwnPropertyKeys(thread, obj, type);
}
JSTaggedValue BuiltinsObject::GetOwnPropertySymbols(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, GetOwnPropertySymbols);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
KeyType type = KeyType::SYMBOL_TYPE;
return GetOwnPropertyKeys(thread, obj, type);
}
JSTaggedValue BuiltinsObject::GetPrototypeOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, GetPrototypeOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> func = GetCallArg(argv, 0);
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, func);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(obj));
}
JSTaggedValue BuiltinsObject::Is(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Object, Is);
bool result = JSTaggedValue::SameValue(argv->GetThread(), GetCallArg(argv, 0), GetCallArg(argv, 1));
return GetTaggedBoolean(result);
}
JSTaggedValue BuiltinsObject::IsExtensible(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, IsExtensible);
JSTaggedValue obj = GetCallArg(argv, 0).GetTaggedValue();
if (!obj.IsECMAObject()) {
return GetTaggedBoolean(false);
}
[[maybe_unused]] EcmaHandleScope handleScope(thread);
return GetTaggedBoolean(obj.IsExtensible(thread));
}
JSTaggedValue BuiltinsObject::IsFrozen(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Object, IsFrozen);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject()) {
return GetTaggedBoolean(true);
}
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
bool status = JSObject::TestIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::FROZEN);
return GetTaggedBoolean(status);
}
JSTaggedValue BuiltinsObject::IsSealed(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Object, IsSealed);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject()) {
return GetTaggedBoolean(true);
}
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
bool status = JSObject::TestIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::SEALED);
return GetTaggedBoolean(status);
}
JSTaggedValue BuiltinsObject::Keys(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Keys);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> nameList = JSObject::EnumerableOwnNames(thread, obj);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSArray> result = JSArray::CreateArrayFromList(thread, nameList);
return result.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::Values(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Values);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> nameList = JSObject::EnumerableOwnPropertyNames(thread, obj, PropertyKind::VALUE);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSArray> result = JSArray::CreateArrayFromList(thread, nameList);
return result.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::PreventExtensions(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, PreventExtensions);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsECMAObject()) {
return obj.GetTaggedValue();
}
[[maybe_unused]] EcmaHandleScope handleScope(thread);
bool status = JSTaggedValue::PreventExtensions(thread, obj);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!status) {
THROW_TYPE_ERROR_AND_RETURN(thread, "PreventExtensions: preventExtensions failed",
JSTaggedValue::Exception());
}
return obj.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::Seal(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, Seal);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
if (!msg->IsECMAObject()) {
return msg.GetTaggedValue();
}
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, msg);
bool status = JSObject::SetIntegrityLevel(thread, object, IntegrityLevel::SEALED);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!status) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Seal: seal failed", JSTaggedValue::Exception());
}
return object.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::SetPrototypeOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, SetPrototypeOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> object = JSTaggedValue::RequireObjectCoercible(thread, GetCallArg(argv, 0));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> proto = GetCallArg(argv, 1);
if (!proto->IsNull() && !proto->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: proto is neither Object nor Null",
JSTaggedValue::Exception());
}
if (!object->IsECMAObject()) {
return object.GetTaggedValue();
}
bool status = JSTaggedValue::SetPrototype(thread, object, proto);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!status) {
THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: prototype set failed", JSTaggedValue::Exception());
}
return object.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::HasOwnProperty(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, HasOwnProperty);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> thisValue = GetThis(argv);
JSHandle<JSTaggedValue> prop = GetCallArg(argv, 0);
return HasOwnPropertyInternal(thread, thisValue, prop);
}
JSTaggedValue BuiltinsObject::HasOwnPropertyInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue,
JSHandle<JSTaggedValue> prop)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
std::pair<JSTaggedValue, bool> result = ObjectFastOperator::HasOwnProperty(thread, thisValue.GetTaggedValue(),
prop.GetTaggedValue());
if (!result.first.IsHole()) {
return GetTaggedBoolean(true);
} else if (result.second) {
return GetTaggedBoolean(false);
}
JSHandle<JSTaggedValue> property = JSTaggedValue::ToPropertyKey(thread, prop);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, thisValue);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool res = JSTaggedValue::HasOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(object), property);
return GetTaggedBoolean(res);
}
JSTaggedValue BuiltinsObject::IsPrototypeOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, IsPrototypeOf);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
if (!msg->IsECMAObject()) {
return GetTaggedBoolean(false);
}
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSMutableHandle<JSTaggedValue> msgValueHandle(thread, msg.GetTaggedValue());
while (!msgValueHandle->IsNull()) {
msgValueHandle.Update(JSTaggedValue::GetPrototype(thread, msgValueHandle));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (JSTaggedValue::SameValue(thread, object.GetTaggedValue(), msgValueHandle.GetTaggedValue())) {
return GetTaggedBoolean(true);
}
}
return GetTaggedBoolean(false);
}
JSTaggedValue BuiltinsObject::PropertyIsEnumerable(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, PropertyIsEnumerable);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> property = JSTaggedValue::ToPropertyKey(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
PropertyDescriptor desc(thread);
JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(object), property, desc);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (desc.IsEmpty()) {
return GetTaggedBoolean(false);
}
return GetTaggedBoolean(desc.IsEnumerable());
}
JSTaggedValue BuiltinsObject::ToLocaleString(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ToLocaleString);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> object = GetThis(argv);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> calleeKey = thread->GlobalConstants()->GetHandledToStringString();
const uint32_t argsLength = argv->GetArgsNumber();
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, object, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(argsLength, 0, argv, 0);
return JSFunction::Invoke(info, calleeKey);
}
JSTaggedValue BuiltinsObject::GetBuiltinObjectToString(JSThread *thread, const JSHandle<JSObject> &object)
{
BUILTINS_API_TRACE(thread, Object, GetBuiltinObjectToString);
bool isArray = object.GetTaggedValue().IsArray(thread);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (isArray) {
return thread->GlobalConstants()->GetArrayToString();
} else if (object->IsJSPrimitiveRef()) {
JSPrimitiveRef *primitiveRef = JSPrimitiveRef::Cast(*object);
if (primitiveRef->IsString(thread)) {
return thread->GlobalConstants()->GetStringToString();
} else if (primitiveRef->IsBoolean(thread)) {
return thread->GlobalConstants()->GetBooleanToString();
} else if (primitiveRef->IsNumber(thread)) {
return thread->GlobalConstants()->GetNumberToString();
}
} else if (object->IsArguments()) {
return thread->GlobalConstants()->GetArgumentsToString();
} else if (object->IsCallable()) {
return thread->GlobalConstants()->GetFunctionToString();
} else if (object->IsJSError()) {
return thread->GlobalConstants()->GetErrorToString();
} else if (object->IsDate()) {
return thread->GlobalConstants()->GetDateToString();
} else if (object->IsJSRegExp()) {
return thread->GlobalConstants()->GetRegExpToString();
}
return thread->GlobalConstants()->GetObjectToString();
}
JSTaggedValue BuiltinsObject::ToString(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ToString);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetThis(argv);
if (msg->IsUndefined()) {
return thread->GlobalConstants()->GetUndefinedToString();
}
if (msg->IsNull()) {
return thread->GlobalConstants()->GetNullToString();
}
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
auto ecmaVm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
auto factory = ecmaVm->GetFactory();
JSHandle<JSTaggedValue> tag = JSTaggedValue::GetProperty(thread, msg,
thread->GlobalConstants()->GetHandledToStringTagSymbol()).GetValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!tag->IsString()) {
return GetBuiltinObjectToString(thread, object);
}
JSHandle<EcmaString> leftString(factory->NewFromASCII("[object "));
JSHandle<EcmaString> rightString(factory->NewFromASCII("]"));
JSHandle<EcmaString> newLeftStringHandle =
factory->ConcatFromString(leftString, JSTaggedValue::ToString(thread, tag));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
auto result = factory->ConcatFromString(newLeftStringHandle, rightString);
return result.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::ValueOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ValueOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return object.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::ProtoGetter(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ProtoGetter);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(obj));
}
JSTaggedValue BuiltinsObject::ProtoSetter(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ProtoSetter);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> proto = GetCallArg(argv, 0);
if (!proto->IsNull() && !proto->IsECMAObject()) {
return JSTaggedValue::Undefined();
}
if (!obj->IsECMAObject()) {
return JSTaggedValue::Undefined();
}
bool status = JSTaggedValue::SetPrototype(thread, obj, proto, true);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!status) {
THROW_TYPE_ERROR_AND_RETURN(thread, "ProtoSetter: proto set failed", JSTaggedValue::Exception());
}
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsObject::CreateRealm(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, CreateRealm);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSObject> realm = factory->CreateJSRealm();
return realm.GetTaggedValue();
}
JSTaggedValue BuiltinsObject::Entries(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, ToString);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, obj);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> nameList = JSObject::EnumerableOwnPropertyNames(thread, object, PropertyKind::KEY_VALUE);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSArray::CreateArrayFromList(thread, nameList).GetTaggedValue();
}
JSTaggedValue BuiltinsObject::FromEntries(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, FromEntries);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> iterable = GetCallArg(argv, 0);
if (iterable->IsUndefined() || iterable->IsNull()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "iterable is undefined or null", JSTaggedValue::Exception());
}
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> constructor(env->GetObjectFunction());
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(constructor);
JSHandle<Method> method(thread,
thread->GetEcmaVM()->GetMethodByIndex(MethodIndex::BUILTINS_OBJECT_CREATE_DATA_PROPERTY_ON_OBJECT_FUNCTIONS));
JSHandle<JSFunction> addrFunc = factory->NewJSFunction(env, method);
addrFunc->SetLexicalEnv(thread, env);
JSHandle<JSTaggedValue> adder(thread, addrFunc.GetTaggedValue());
return BuiltinsMap::AddEntriesFromIterable(thread, obj, iterable, adder, factory);
}
JSTaggedValue BuiltinsObject::CreateDataPropertyOnObjectFunctions(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, CreateDataPropertyOnObjectFunctions);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
JSHandle<JSObject> thisObjHandle = JSHandle<JSObject>::Cast(thisHandle);
ASSERT(thisHandle->IsHeapObject());
JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> propertyKey = JSTaggedValue::ToPropertyKey(thread, key);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSObject::CreateDataPropertyOrThrow(thread, thisObjHandle, propertyKey, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsObject::HasOwn(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Object, HasOwn);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, obj);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> prop = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, prop);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bool res = JSTaggedValue::HasOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(object), key);
return GetTaggedBoolean(res);
}
}