/* * 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 "ecma_string_table.h" #include "ecma_vm.h" #include "ecmascript/accessor_data.h" #include "ecmascript/base/error_helper.h" #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_errors.h" #include "ecmascript/builtins/builtins_global.h" #include "ecmascript/class_info_extractor.h" #include "ecmascript/class_linker/program_object.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_module.h" #include "ecmascript/free_object.h" #include "ecmascript/global_env.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/global_env_constants.h" #include "ecmascript/ic/ic_handler.h" #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/ic/property_box.h" #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_api_tree_map.h" #include "ecmascript/js_api_tree_map_iterator.h" #include "ecmascript/js_api_tree_set.h" #include "ecmascript/js_api_tree_set_iterator.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_api_arraylist.h" #include "ecmascript/js_api_arraylist_iterator.h" #include "ecmascript/js_async_function.h" #include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_hclass-inl.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_iterator.h" #include "ecmascript/js_map.h" #include "ecmascript/js_map_iterator.h" #include "ecmascript/js_object-inl.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_proxy.h" #include "ecmascript/js_realm.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" #include "ecmascript/js_string_iterator.h" #include "ecmascript/js_symbol.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/js_weak_container.h" #include "ecmascript/layout_info-inl.h" #include "ecmascript/linked_hash_table-inl.h" #include "ecmascript/mem/mem_manager.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/space.h" #include "ecmascript/record.h" #include "ecmascript/symbol_table-inl.h" #include "ecmascript/tagged_tree-inl.h" #include "ecmascript/template_map.h" namespace panda::ecmascript { using Error = builtins::BuiltinsError; using RangeError = builtins::BuiltinsRangeError; using ReferenceError = builtins::BuiltinsReferenceError; using TypeError = builtins::BuiltinsTypeError; using URIError = builtins::BuiltinsURIError; using SyntaxError = builtins::BuiltinsSyntaxError; using EvalError = builtins::BuiltinsEvalError; using ErrorType = base::ErrorType; using ErrorHelper = base::ErrorHelper; ObjectFactory::ObjectFactory(JSThread *thread, Heap *heap) : thread_(thread), heapHelper_(heap), vm_(thread->GetEcmaVM()), heap_(heap) { } JSHandle ObjectFactory::NewEcmaDynClassClass(JSHClass *hclass, uint32_t size, JSType type) { NewObjectHook(); uint32_t classSize = JSHClass::SIZE; auto *newClass = static_cast(heapHelper_.AllocateDynClassClass(hclass, classSize)); newClass->Initialize(thread_, size, type, 0); return JSHandle(thread_, newClass); } JSHandle ObjectFactory::NewEcmaDynClass(JSHClass *hclass, uint32_t size, JSType type, uint32_t inlinedProps) { NewObjectHook(); uint32_t classSize = JSHClass::SIZE; auto *newClass = static_cast(heapHelper_.AllocateNonMovableOrHugeObject(hclass, classSize)); newClass->Initialize(thread_, size, type, inlinedProps); return JSHandle(thread_, newClass); } JSHandle ObjectFactory::NewEcmaDynClass(uint32_t size, JSType type, uint32_t inlinedProps) { return NewEcmaDynClass(JSHClass::Cast(thread_->GlobalConstants()->GetHClassClass().GetTaggedObject()), size, type, inlinedProps); } void ObjectFactory::InitObjectFields(const TaggedObject *object) { auto *klass = object->GetClass(); auto objBodySize = klass->GetObjectSize() - TaggedObject::TaggedObjectSize(); ASSERT(objBodySize % JSTaggedValue::TaggedTypeSize() == 0); int numOfFields = static_cast(objBodySize / JSTaggedValue::TaggedTypeSize()); size_t addr = reinterpret_cast(object) + TaggedObject::TaggedObjectSize(); for (int i = 0; i < numOfFields; i++) { auto *fieldAddr = reinterpret_cast(addr + i * JSTaggedValue::TaggedTypeSize()); *fieldAddr = JSTaggedValue::Undefined().GetRawData(); } } void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, int32_t length) { if (length == 0) { return; } JSTaggedValue data = array->GetArrayBufferData(); if (data != JSTaggedValue::Undefined()) { auto *pointer = JSNativePointer::Cast(data.GetTaggedObject()); auto newData = vm_->GetNativeAreaAllocator()->AllocateBuffer(length * sizeof(uint8_t)); if (memset_s(newData, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); } pointer->ResetExternalPointer(newData); return; } auto newData = vm_->GetNativeAreaAllocator()->AllocateBuffer(length * sizeof(uint8_t)); if (memset_s(newData, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); } JSHandle pointer = NewJSNativePointer(newData, NativeAreaAllocator::FreeBufferFunc, vm_->GetNativeAreaAllocator()); array->SetArrayBufferData(thread_, pointer.GetTaggedValue()); vm_->PushToArrayDataList(*pointer); } JSHandle ObjectFactory::NewJSArrayBuffer(int32_t length) { JSHandle env = vm_->GetGlobalEnv(); JSHandle constructor(env->GetArrayBufferFunction()); JSHandle newTarget(constructor); JSHandle arrayBuffer(NewJSObjectByConstructor(constructor, newTarget)); arrayBuffer->SetArrayBufferByteLength(length); if (length > 0) { auto newData = vm_->GetNativeAreaAllocator()->AllocateBuffer(length); if (memset_s(newData, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); } JSHandle pointer = NewJSNativePointer(newData, NativeAreaAllocator::FreeBufferFunc, vm_->GetNativeAreaAllocator()); arrayBuffer->SetArrayBufferData(thread_, pointer.GetTaggedValue()); arrayBuffer->ClearBitField(); vm_->PushToArrayDataList(*pointer); } return arrayBuffer; } JSHandle ObjectFactory::NewJSArrayBuffer(void *buffer, int32_t length, const DeleteEntryPoint &deleter, void *data, bool share) { JSHandle env = vm_->GetGlobalEnv(); JSHandle constructor(env->GetArrayBufferFunction()); JSHandle newTarget(constructor); JSHandle arrayBuffer(NewJSObjectByConstructor(constructor, newTarget)); length = buffer == nullptr ? 0 : length; arrayBuffer->SetArrayBufferByteLength(length); if (length > 0) { JSHandle pointer = NewJSNativePointer(buffer, deleter, data); arrayBuffer->SetArrayBufferData(thread_, pointer.GetTaggedValue()); arrayBuffer->SetShared(share); vm_->PushToArrayDataList(*pointer); } return arrayBuffer; } JSHandle ObjectFactory::NewJSDataView(JSHandle buffer, uint32_t offset, uint32_t length) { uint32_t arrayLength = buffer->GetArrayBufferByteLength(); if (arrayLength - offset < length) { THROW_TYPE_ERROR_AND_RETURN(thread_, "offset or length error", JSHandle(thread_, JSTaggedValue::Undefined())); } JSHandle env = vm_->GetGlobalEnv(); JSHandle constructor(env->GetDataViewFunction()); JSHandle newTarget(constructor); JSHandle arrayBuffer(NewJSObjectByConstructor(constructor, newTarget)); arrayBuffer->SetDataView(thread_, JSTaggedValue::True()); arrayBuffer->SetViewedArrayBuffer(thread_, buffer.GetTaggedValue()); arrayBuffer->SetByteLength(length); arrayBuffer->SetByteOffset(offset); return arrayBuffer; } void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, void *buffer, size_t size) { if (buffer == nullptr) { return; } auto newBuffer = vm_->GetNativeAreaAllocator()->AllocateBuffer(size); if (memcpy_s(newBuffer, size, buffer, size) != EOK) { LOG_ECMA(FATAL) << "memcpy_s failed"; UNREACHABLE(); } JSTaggedValue data = regexp->GetByteCodeBuffer(); if (data != JSTaggedValue::Undefined()) { JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); native->ResetExternalPointer(newBuffer); return; } JSHandle pointer = NewJSNativePointer(newBuffer, NativeAreaAllocator::FreeBufferFunc, vm_->GetNativeAreaAllocator()); regexp->SetByteCodeBuffer(thread_, pointer.GetTaggedValue()); regexp->SetLength(static_cast(size)); // push uint8_t* to ecma array_data_list vm_->PushToArrayDataList(*pointer); } JSHandle ObjectFactory::NewEcmaDynClass(uint32_t size, JSType type, const JSHandle &prototype) { JSHandle newClass = NewEcmaDynClass(size, type); newClass->SetPrototype(thread_, prototype.GetTaggedValue()); return newClass; } JSHandle ObjectFactory::NewJSObject(const JSHandle &jshclass) { JSHandle obj(thread_, JSObject::Cast(NewDynObject(jshclass))); JSHandle emptyArray = EmptyArray(); obj->InitializeHash(); obj->SetElements(thread_, emptyArray, SKIP_BARRIER); obj->SetProperties(thread_, emptyArray, SKIP_BARRIER); return obj; } JSHandle ObjectFactory::CloneProperties(const JSHandle &old) { uint32_t newLength = old->GetLength(); if (newLength == 0) { return EmptyArray(); } NewObjectHook(); auto klass = old->GetClass(); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject(klass, size); JSHandle newArray(thread_, header); newArray->SetLength(newLength); for (uint32_t i = 0; i < newLength; i++) { JSTaggedValue value = old->Get(i); newArray->Set(thread_, i, value); } return newArray; } JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object) { NewObjectHook(); auto klass = JSHandle(thread_, object->GetClass()); JSHandle cloneObject = NewJSObject(klass); JSHandle elements(thread_, object->GetElements()); auto newElements = CloneProperties(elements); cloneObject->SetElements(thread_, newElements.GetTaggedValue()); JSHandle properties(thread_, object->GetProperties()); auto newProperties = CloneProperties(properties); cloneObject->SetProperties(thread_, newProperties.GetTaggedValue()); for (uint32_t i = 0; i < klass->GetInlinedProperties(); i++) { cloneObject->SetPropertyInlinedProps(thread_, i, object->GetPropertyInlinedProps(i)); } return cloneObject; } JSHandle ObjectFactory::CloneArrayLiteral(JSHandle object) { NewObjectHook(); auto klass = JSHandle(thread_, object->GetClass()); JSHandle cloneObject(NewJSObject(klass)); cloneObject->SetArrayLength(thread_, object->GetArrayLength()); JSHandle elements(thread_, object->GetElements()); auto newElements = CopyArray(elements, elements->GetLength(), elements->GetLength()); cloneObject->SetElements(thread_, newElements.GetTaggedValue()); JSHandle properties(thread_, object->GetProperties()); auto newProperties = CopyArray(properties, properties->GetLength(), properties->GetLength()); cloneObject->SetProperties(thread_, newProperties.GetTaggedValue()); for (uint32_t i = 0; i < klass->GetInlinedProperties(); i++) { cloneObject->SetPropertyInlinedProps(thread_, i, object->GetPropertyInlinedProps(i)); } return cloneObject; } JSHandle ObjectFactory::CloneProperties(const JSHandle &old, const JSHandle &env, const JSHandle &obj, const JSHandle &constpool) { uint32_t newLength = old->GetLength(); if (newLength == 0) { return EmptyArray(); } NewObjectHook(); JSHandle newArray = NewTaggedArray(newLength); for (uint32_t i = 0; i < newLength; i++) { JSTaggedValue value = old->Get(i); if (!value.IsJSFunction()) { newArray->Set(thread_, i, value); } else { JSHandle valueHandle(thread_, value); JSHandle newFunc = CloneJSFuction(valueHandle, valueHandle->GetFunctionKind()); newFunc->SetLexicalEnv(thread_, env); newFunc->SetHomeObject(thread_, obj); newFunc->SetConstantPool(thread_, constpool); newArray->Set(thread_, i, newFunc); } } return newArray; } JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object, const JSHandle &env, const JSHandle &constpool, bool canShareHClass) { NewObjectHook(); auto klass = JSHandle(thread_, object->GetClass()); if (!canShareHClass) { klass = JSHClass::Clone(thread_, klass); } JSHandle cloneObject = NewJSObject(klass); JSHandle elements(thread_, object->GetElements()); auto newElements = CloneProperties(elements, env, cloneObject, constpool); cloneObject->SetElements(thread_, newElements.GetTaggedValue()); JSHandle properties(thread_, object->GetProperties()); auto newProperties = CloneProperties(properties, env, cloneObject, constpool); cloneObject->SetProperties(thread_, newProperties.GetTaggedValue()); for (uint32_t i = 0; i < klass->GetInlinedProperties(); i++) { JSTaggedValue value = object->GetPropertyInlinedProps(i); if (!value.IsJSFunction()) { cloneObject->SetPropertyInlinedProps(thread_, i, value); } else { JSHandle valueHandle(thread_, value); JSHandle newFunc = CloneJSFuction(valueHandle, valueHandle->GetFunctionKind()); newFunc->SetLexicalEnv(thread_, env); newFunc->SetHomeObject(thread_, cloneObject); newFunc->SetConstantPool(thread_, constpool); cloneObject->SetPropertyInlinedProps(thread_, i, newFunc.GetTaggedValue()); } } return cloneObject; } JSHandle ObjectFactory::CloneJSFuction(JSHandle obj, FunctionKind kind) { JSHandle env = vm_->GetGlobalEnv(); JSHandle jshclass(thread_, obj->GetJSHClass()); JSHandle cloneFunc = NewJSFunctionByDynClass(obj->GetCallTarget(), jshclass, kind); if (kind == FunctionKind::GENERATOR_FUNCTION) { JSHandle objFun = env->GetObjectFunction(); JSHandle initialGeneratorFuncPrototype = NewJSObjectByConstructor(JSHandle(objFun), objFun); JSObject::SetPrototype(thread_, initialGeneratorFuncPrototype, env->GetGeneratorPrototype()); cloneFunc->SetProtoOrDynClass(thread_, initialGeneratorFuncPrototype); } JSTaggedValue length = obj->GetPropertyInlinedProps(JSFunction::LENGTH_INLINE_PROPERTY_INDEX); cloneFunc->SetPropertyInlinedProps(thread_, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, length); return cloneFunc; } JSHandle ObjectFactory::CloneClassCtor(JSHandle ctor, const JSHandle &lexenv, bool canShareHClass) { NewObjectHook(); JSHandle constpool(thread_, ctor->GetConstantPool()); JSHandle hclass(thread_, ctor->GetClass()); if (!canShareHClass) { hclass = JSHClass::Clone(thread_, hclass); } FunctionKind kind = ctor->GetFunctionKind(); ASSERT_PRINT(kind == FunctionKind::CLASS_CONSTRUCTOR || kind == FunctionKind::DERIVED_CONSTRUCTOR, "cloned function is not class"); JSHandle cloneCtor = NewJSFunctionByDynClass(ctor->GetCallTarget(), hclass, kind); for (uint32_t i = 0; i < hclass->GetInlinedProperties(); i++) { JSTaggedValue value = ctor->GetPropertyInlinedProps(i); if (!value.IsJSFunction()) { cloneCtor->SetPropertyInlinedProps(thread_, i, value); } else { JSHandle valueHandle(thread_, value); JSHandle newFunc = CloneJSFuction(valueHandle, valueHandle->GetFunctionKind()); newFunc->SetLexicalEnv(thread_, lexenv); newFunc->SetHomeObject(thread_, cloneCtor); newFunc->SetConstantPool(thread_, constpool); cloneCtor->SetPropertyInlinedProps(thread_, i, newFunc.GetTaggedValue()); } } JSHandle elements(thread_, ctor->GetElements()); auto newElements = CloneProperties(elements, lexenv, JSHandle(cloneCtor), constpool); cloneCtor->SetElements(thread_, newElements.GetTaggedValue()); JSHandle properties(thread_, ctor->GetProperties()); auto newProperties = CloneProperties(properties, lexenv, JSHandle(cloneCtor), constpool); cloneCtor->SetProperties(thread_, newProperties.GetTaggedValue()); cloneCtor->SetConstantPool(thread_, constpool); return cloneCtor; } JSHandle ObjectFactory::NewNonMovableJSObject(const JSHandle &jshclass) { JSHandle obj(thread_, JSObject::Cast(NewNonMovableDynObject(jshclass, jshclass->GetInlinedProperties()))); obj->SetElements(thread_, EmptyArray(), SKIP_BARRIER); obj->SetProperties(thread_, EmptyArray(), SKIP_BARRIER); return obj; } JSHandle ObjectFactory::NewJSPrimitiveRef(const JSHandle &dynKlass, const JSHandle &object) { JSHandle obj = JSHandle::Cast(NewJSObject(dynKlass)); obj->SetValue(thread_, object); return obj; } JSHandle ObjectFactory::NewJSArray() { JSHandle env = vm_->GetGlobalEnv(); JSHandle function = env->GetArrayFunction(); return JSHandle(NewJSObjectByConstructor(JSHandle(function), function)); } JSHandle ObjectFactory::NewJSForinIterator(const JSHandle &obj) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass(env->GetForinIteratorClass()); JSHandle it = JSHandle::Cast(NewJSObject(dynclass)); it->SetObject(thread_, obj); it->SetVisitedKeys(thread_, env->GetEmptyTaggedQueue()); it->SetRemainingKeys(thread_, env->GetEmptyTaggedQueue()); it->ClearBitField(); return it; } JSHandle ObjectFactory::CreateJSRegExpInstanceClass(JSHandle proto) { const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle regexpDynclass = NewEcmaDynClass(JSRegExp::SIZE, JSType::JS_REG_EXP, proto); uint32_t fieldOrder = 0; JSHandle layoutInfoHandle = CreateLayoutInfo(1); { PropertyAttributes attributes = PropertyAttributes::Default(true, false, false); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, 0, globalConst->GetLastIndexString(), attributes); } { regexpDynclass->SetLayout(thread_, layoutInfoHandle); regexpDynclass->SetNumberOfProps(fieldOrder); } return regexpDynclass; } JSHandle ObjectFactory::CreateJSArrayInstanceClass(JSHandle proto) { const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle arrayDynclass = NewEcmaDynClass(JSArray::SIZE, JSType::JS_ARRAY, proto); uint32_t fieldOrder = 0; ASSERT(JSArray::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); JSHandle layoutInfoHandle = CreateLayoutInfo(1); { PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(true, false, false); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, 0, globalConst->GetLengthString(), attributes); } { arrayDynclass->SetLayout(thread_, layoutInfoHandle); arrayDynclass->SetNumberOfProps(fieldOrder); } arrayDynclass->SetIsStableElements(true); arrayDynclass->SetHasConstructor(false); return arrayDynclass; } JSHandle ObjectFactory::CreateJSArguments() { JSHandle env = thread_->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle proto = env->GetObjectFunctionPrototype(); JSHandle argumentsDynclass = NewEcmaDynClass(JSArguments::SIZE, JSType::JS_ARGUMENTS, proto); uint32_t fieldOrder = 0; ASSERT(JSArguments::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); JSHandle layoutInfoHandle = CreateLayoutInfo(JSArguments::LENGTH_OF_INLINE_PROPERTIES); { PropertyAttributes attributes = PropertyAttributes::Default(true, false, true); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, JSArguments::LENGTH_INLINE_PROPERTY_INDEX, globalConst->GetLengthString(), attributes); } ASSERT(JSArguments::ITERATOR_INLINE_PROPERTY_INDEX == fieldOrder); { PropertyAttributes attributes = PropertyAttributes::Default(true, false, true); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, JSArguments::ITERATOR_INLINE_PROPERTY_INDEX, env->GetIteratorSymbol().GetTaggedValue(), attributes); } { ASSERT(JSArguments::CALLER_INLINE_PROPERTY_INDEX == fieldOrder); PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); attributes.SetIsInlinedProps(true); attributes.SetIsAccessor(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, JSArguments::CALLER_INLINE_PROPERTY_INDEX, thread_->GlobalConstants()->GetHandledCallerString().GetTaggedValue(), attributes); } { ASSERT(JSArguments::CALLEE_INLINE_PROPERTY_INDEX == fieldOrder); PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); attributes.SetIsInlinedProps(true); attributes.SetIsAccessor(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder++); layoutInfoHandle->AddKey(thread_, JSArguments::CALLEE_INLINE_PROPERTY_INDEX, thread_->GlobalConstants()->GetHandledCalleeString().GetTaggedValue(), attributes); } { argumentsDynclass->SetLayout(thread_, layoutInfoHandle); argumentsDynclass->SetNumberOfProps(fieldOrder); } argumentsDynclass->SetIsStableElements(true); return argumentsDynclass; } JSHandle ObjectFactory::NewJSArguments() { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetArgumentsClass()); JSHandle obj = JSHandle::Cast(NewJSObject(dynclass)); return obj; } JSHandle ObjectFactory::GetJSError(const ErrorType &errorType, const char *data) { ASSERT_PRINT(errorType == ErrorType::ERROR || errorType == ErrorType::EVAL_ERROR || errorType == ErrorType::RANGE_ERROR || errorType == ErrorType::REFERENCE_ERROR || errorType == ErrorType::SYNTAX_ERROR || errorType == ErrorType::TYPE_ERROR || errorType == ErrorType::URI_ERROR, "The error type is not in the valid range."); if (data != nullptr) { JSHandle handleMsg = NewFromString(data); return NewJSError(errorType, handleMsg); } JSHandle emptyString(thread_->GlobalConstants()->GetHandledEmptyString()); return NewJSError(errorType, emptyString); } JSHandle ObjectFactory::NewJSError(const ErrorType &errorType, const JSHandle &message) { JSHandle env = vm_->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle nativeConstructor; switch (errorType) { case ErrorType::RANGE_ERROR: nativeConstructor = env->GetRangeErrorFunction(); break; case ErrorType::EVAL_ERROR: nativeConstructor = env->GetEvalErrorFunction(); break; case ErrorType::REFERENCE_ERROR: nativeConstructor = env->GetReferenceErrorFunction(); break; case ErrorType::TYPE_ERROR: nativeConstructor = env->GetTypeErrorFunction(); break; case ErrorType::URI_ERROR: nativeConstructor = env->GetURIErrorFunction(); break; case ErrorType::SYNTAX_ERROR: nativeConstructor = env->GetSyntaxErrorFunction(); break; default: nativeConstructor = env->GetErrorFunction(); break; } JSHandle nativeFunc = JSHandle::Cast(nativeConstructor); JSHandle nativePrototype(thread_, nativeFunc->GetFunctionPrototype()); JSHandle ctorKey = globalConst->GetHandledConstructorString(); InternalCallParams *arguments = thread_->GetInternalCallParams(); arguments->MakeArgv(message.GetTaggedValue()); JSTaggedValue obj = JSFunction::Invoke(thread_, nativePrototype, ctorKey, 1, arguments->GetArgv()); JSHandle handleNativeInstanceObj(thread_, obj); return handleNativeInstanceObj; } JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandle &constructor, const JSHandle &newTarget) { JSHandle jshclass; if (!constructor->HasFunctionPrototype() || (constructor->GetProtoOrDynClass().IsHeapObject() && constructor->GetFunctionPrototype().IsECMAObject())) { jshclass = JSFunction::GetInstanceJSHClass(thread_, constructor, newTarget); } else { JSHandle env = vm_->GetGlobalEnv(); jshclass = JSFunction::GetInstanceJSHClass(thread_, JSHandle(env->GetObjectFunction()), newTarget); } // Check this exception elsewhere RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread_); JSHandle obj = NewJSObject(jshclass); { JSType type = jshclass->GetObjectType(); switch (type) { case JSType::JS_OBJECT: case JSType::JS_ERROR: case JSType::JS_EVAL_ERROR: case JSType::JS_RANGE_ERROR: case JSType::JS_REFERENCE_ERROR: case JSType::JS_TYPE_ERROR: case JSType::JS_URI_ERROR: case JSType::JS_SYNTAX_ERROR: case JSType::JS_ITERATOR: case JSType::JS_INTL: case JSType::JS_LOCALE: case JSType::JS_DATE_TIME_FORMAT: case JSType::JS_NUMBER_FORMAT: case JSType::JS_RELATIVE_TIME_FORMAT: case JSType::JS_COLLATOR: case JSType::JS_PLURAL_RULES: break; case JSType::JS_ARRAY: { JSArray::Cast(*obj)->SetLength(thread_, JSTaggedValue(0)); auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor(); JSArray::Cast(*obj)->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor); break; } case JSType::JS_DATE: JSDate::Cast(*obj)->SetTimeValue(thread_, JSTaggedValue(0.0)); JSDate::Cast(*obj)->SetLocalOffset(thread_, JSTaggedValue(JSDate::MAX_DOUBLE)); break; case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: case JSType::JS_UINT8_CLAMPED_ARRAY: case JSType::JS_INT16_ARRAY: case JSType::JS_UINT16_ARRAY: case JSType::JS_INT32_ARRAY: case JSType::JS_UINT32_ARRAY: case JSType::JS_FLOAT32_ARRAY: case JSType::JS_FLOAT64_ARRAY: JSTypedArray::Cast(*obj)->SetViewedArrayBuffer(thread_, JSTaggedValue::Undefined()); JSTypedArray::Cast(*obj)->SetTypedArrayName(thread_, JSTaggedValue::Undefined()); JSTypedArray::Cast(*obj)->SetByteLength(thread_, JSTaggedValue(0)); JSTypedArray::Cast(*obj)->SetByteOffset(thread_, JSTaggedValue(0)); JSTypedArray::Cast(*obj)->SetArrayLength(thread_, JSTaggedValue(0)); break; case JSType::JS_REG_EXP: JSRegExp::Cast(*obj)->SetByteCodeBuffer(thread_, JSTaggedValue::Undefined()); JSRegExp::Cast(*obj)->SetOriginalSource(thread_, JSTaggedValue::Undefined()); JSRegExp::Cast(*obj)->SetOriginalFlags(thread_, JSTaggedValue(0)); JSRegExp::Cast(*obj)->SetLength(0); break; case JSType::JS_PRIMITIVE_REF: JSPrimitiveRef::Cast(*obj)->SetValue(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_SET: JSSet::Cast(*obj)->SetLinkedSet(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_MAP: JSMap::Cast(*obj)->SetLinkedMap(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_WEAK_MAP: JSWeakMap::Cast(*obj)->SetLinkedMap(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_WEAK_SET: JSWeakSet::Cast(*obj)->SetLinkedSet(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_GENERATOR_OBJECT: JSGeneratorObject::Cast(*obj)->SetGeneratorContext(thread_, JSTaggedValue::Undefined()); JSGeneratorObject::Cast(*obj)->SetResumeResult(thread_, JSTaggedValue::Undefined()); JSGeneratorObject::Cast(*obj)->SetGeneratorState(JSGeneratorState::UNDEFINED); JSGeneratorObject::Cast(*obj)->SetResumeMode(GeneratorResumeMode::UNDEFINED); break; case JSType::JS_STRING_ITERATOR: JSStringIterator::Cast(*obj)->SetStringIteratorNextIndex(0); JSStringIterator::Cast(*obj)->SetIteratedString(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_ARRAY_BUFFER: JSArrayBuffer::Cast(*obj)->SetArrayBufferData(thread_, JSTaggedValue::Undefined()); JSArrayBuffer::Cast(*obj)->SetArrayBufferByteLength(0); JSArrayBuffer::Cast(*obj)->ClearBitField(); break; case JSType::JS_PROMISE: JSPromise::Cast(*obj)->SetPromiseState(PromiseState::PENDING); JSPromise::Cast(*obj)->SetPromiseResult(thread_, JSTaggedValue::Undefined()); JSPromise::Cast(*obj)->SetPromiseRejectReactions(thread_, GetEmptyTaggedQueue().GetTaggedValue()); JSPromise::Cast(*obj)->SetPromiseFulfillReactions(thread_, GetEmptyTaggedQueue().GetTaggedValue()); JSPromise::Cast(*obj)->SetPromiseIsHandled(false); break; case JSType::JS_DATA_VIEW: JSDataView::Cast(*obj)->SetDataView(thread_, JSTaggedValue(false)); JSDataView::Cast(*obj)->SetViewedArrayBuffer(thread_, JSTaggedValue::Undefined()); JSDataView::Cast(*obj)->SetByteLength(0); JSDataView::Cast(*obj)->SetByteOffset(0); break; // non ECMA standard jsapi container case JSType::JS_API_ARRAY_LIST: JSAPIArrayList::Cast(*obj)->SetLength(thread_, JSTaggedValue(0)); break; case JSType::JS_API_TREE_MAP: JSAPITreeMap::Cast(*obj)->SetTreeMap(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_API_TREE_SET: JSAPITreeSet::Cast(*obj)->SetTreeSet(thread_, JSTaggedValue::Undefined()); break; case JSType::JS_FUNCTION: case JSType::JS_GENERATOR_FUNCTION: case JSType::JS_FORIN_ITERATOR: case JSType::JS_MAP_ITERATOR: case JSType::JS_SET_ITERATOR: case JSType::JS_API_ARRAYLIST_ITERATOR: case JSType::JS_API_TREEMAP_ITERATOR: case JSType::JS_API_TREESET_ITERATOR: case JSType::JS_ARRAY_ITERATOR: default: UNREACHABLE(); } } return obj; } FreeObject *ObjectFactory::FillFreeObject(uintptr_t address, size_t size, RemoveSlots removeSlots) { FreeObject *object = nullptr; const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); if (size >= FreeObject::SIZE_OFFSET && size < FreeObject::SIZE) { object = reinterpret_cast(address); object->SetClassWithoutBarrier(JSHClass::Cast(globalConst->GetFreeObjectWithOneFieldClass().GetTaggedObject())); object->SetNext(nullptr); } else if (size >= FreeObject::SIZE) { object = reinterpret_cast(address); bool firstHClassLoaded = false; if (!firstHClassLoaded && !globalConst->GetFreeObjectWithTwoFieldClass().GetRawData()) { object->SetClassWithoutBarrier(nullptr); firstHClassLoaded = true; } else { object->SetClassWithoutBarrier( JSHClass::Cast(globalConst->GetFreeObjectWithTwoFieldClass().GetTaggedObject())); } object->SetAvailable(size); object->SetNext(nullptr); } else if (size == FreeObject::NEXT_OFFSET) { object = reinterpret_cast(address); object->SetClassWithoutBarrier( JSHClass::Cast(globalConst->GetFreeObjectWithNoneFieldClass().GetTaggedObject())); } else { LOG_ECMA(DEBUG) << "Fill free object size is smaller"; } if (removeSlots == RemoveSlots::YES) { Region *region = Region::ObjectAddressToRange(object); if (!region->InYoungGeneration()) { heap_->ClearSlotsRange(region, address, address + size); } } return object; } TaggedObject *ObjectFactory::NewDynObject(const JSHandle &dynclass) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject(*dynclass); uint32_t inobjPropCount = dynclass->GetInlinedProperties(); if (inobjPropCount > 0) { InitializeExtraProperties(dynclass, header, inobjPropCount); } return header; } TaggedObject *ObjectFactory::NewNonMovableDynObject(const JSHandle &dynclass, int inobjPropCount) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateNonMovableOrHugeObject(*dynclass); if (inobjPropCount > 0) { InitializeExtraProperties(dynclass, header, inobjPropCount); } return header; } void ObjectFactory::InitializeExtraProperties(const JSHandle &dynclass, TaggedObject *obj, int inobjPropCount) { ASSERT(inobjPropCount * JSTaggedValue::TaggedTypeSize() < dynclass->GetObjectSize()); auto paddr = reinterpret_cast(obj) + dynclass->GetObjectSize(); JSTaggedType initVal = JSTaggedValue::Undefined().GetRawData(); for (int i = 0; i < inobjPropCount; ++i) { paddr -= JSTaggedValue::TaggedTypeSize(); *reinterpret_cast(paddr) = initVal; } } JSHandle ObjectFactory::OrdinaryNewJSObjectCreate(const JSHandle &proto) { JSHandle protoValue(proto); JSHandle protoDyn = NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, protoValue); JSHandle newObj = NewJSObject(protoDyn); newObj->GetJSHClass()->SetExtensible(true); return newObj; } JSHandle ObjectFactory::NewJSFunction(const JSHandle &env, const void *nativeFunc, FunctionKind kind) { JSMethod *target = vm_->GetMethodForNativeFunction(nativeFunc); return NewJSFunction(env, target, kind); } JSHandle ObjectFactory::NewJSFunction(const JSHandle &env, JSMethod *method, FunctionKind kind) { JSHandle dynclass; if (kind == FunctionKind::BASE_CONSTRUCTOR) { dynclass = JSHandle::Cast(env->GetFunctionClassWithProto()); } else if (JSFunction::IsConstructorKind(kind)) { dynclass = JSHandle::Cast(env->GetConstructorFunctionClass()); } else { dynclass = JSHandle::Cast(env->GetNormalFunctionClass()); } return NewJSFunctionByDynClass(method, dynclass, kind); } JSHandle ObjectFactory::CreateFunctionClass(FunctionKind kind, uint32_t size, JSType type, const JSHandle &prototype) { const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle functionClass = NewEcmaDynClass(size, type, prototype); { functionClass->SetCallable(true); // FunctionKind = BASE_CONSTRUCTOR if (JSFunction::IsConstructorKind(kind)) { functionClass->SetConstructor(true); } functionClass->SetExtensible(true); } uint32_t fieldOrder = 0; ASSERT(JSFunction::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); JSHandle layoutInfoHandle = CreateLayoutInfo(JSFunction::LENGTH_OF_INLINE_PROPERTIES); { PropertyAttributes attributes = PropertyAttributes::Default(false, false, true); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder); layoutInfoHandle->AddKey(thread_, fieldOrder, globalConst->GetLengthString(), attributes); fieldOrder++; } ASSERT(JSFunction::NAME_INLINE_PROPERTY_INDEX == fieldOrder); // not set name in-object property on class which may have a name() method if (!JSFunction::IsClassConstructor(kind)) { PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(false, false, true); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder); layoutInfoHandle->AddKey(thread_, fieldOrder, thread_->GlobalConstants()->GetHandledNameString().GetTaggedValue(), attributes); fieldOrder++; } if (JSFunction::HasPrototype(kind) && !JSFunction::IsClassConstructor(kind)) { ASSERT(JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX == fieldOrder); PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(true, false, false); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder); layoutInfoHandle->AddKey(thread_, fieldOrder, globalConst->GetPrototypeString(), attributes); fieldOrder++; } else if (JSFunction::IsClassConstructor(kind)) { ASSERT(JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX == fieldOrder); PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(false, false, false); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder); layoutInfoHandle->AddKey(thread_, fieldOrder, globalConst->GetPrototypeString(), attributes); fieldOrder++; } { functionClass->SetLayout(thread_, layoutInfoHandle); functionClass->SetNumberOfProps(fieldOrder); } return functionClass; } JSHandle ObjectFactory::NewJSFunctionByDynClass(JSMethod *method, const JSHandle &clazz, FunctionKind kind) { JSHandle function = JSHandle::Cast(NewJSObject(clazz)); clazz->SetCallable(true); clazz->SetExtensible(true); JSFunction::InitializeJSFunction(thread_, function, kind); function->SetCallTarget(thread_, method); return function; } JSHandle ObjectFactory::NewJSNativeErrorFunction(const JSHandle &env, const void *nativeFunc) { JSMethod *target = vm_->GetMethodForNativeFunction(nativeFunc); JSHandle dynclass = JSHandle::Cast(env->GetNativeErrorFunctionClass()); return NewJSFunctionByDynClass(target, dynclass, FunctionKind::BUILTIN_CONSTRUCTOR); } JSHandle ObjectFactory::NewSpecificTypedArrayFunction(const JSHandle &env, const void *nativeFunc) { JSMethod *target = vm_->GetMethodForNativeFunction(nativeFunc); JSHandle dynclass = JSHandle::Cast(env->GetSpecificTypedArrayFunctionClass()); return NewJSFunctionByDynClass(target, dynclass, FunctionKind::BUILTIN_CONSTRUCTOR); } JSHandle ObjectFactory::NewJSBoundFunction(const JSHandle &target, const JSHandle &boundThis, const JSHandle &args) { JSHandle env = vm_->GetGlobalEnv(); JSHandle proto = env->GetFunctionPrototype(); JSHandle dynclass = NewEcmaDynClass(JSBoundFunction::SIZE, JSType::JS_BOUND_FUNCTION, proto); JSHandle bundleFunction = JSHandle::Cast(NewJSObject(dynclass)); bundleFunction->SetBoundTarget(thread_, target); bundleFunction->SetBoundThis(thread_, boundThis); bundleFunction->SetBoundArguments(thread_, args); dynclass->SetCallable(true); if (target.GetTaggedValue().IsConstructor()) { bundleFunction->SetConstructor(true); } JSMethod *method = vm_->GetMethodForNativeFunction(reinterpret_cast(builtins::BuiltinsGlobal::CallJsBoundFunction)); bundleFunction->SetCallTarget(thread_, method); return bundleFunction; } JSHandle ObjectFactory::NewJSIntlBoundFunction(const void *nativeFunc, int functionLength) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetJSIntlBoundFunctionClass()); JSHandle intlBoundFunc = JSHandle::Cast(NewJSObject(dynclass)); JSMethod *method = vm_->GetMethodForNativeFunction(nativeFunc); intlBoundFunc->SetCallTarget(thread_, method); JSHandle function = JSHandle::Cast(intlBoundFunc); JSFunction::InitializeJSFunction(thread_, function, FunctionKind::NORMAL_FUNCTION); JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(functionLength)); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle emptyString = globalConst->GetHandledEmptyString(); JSHandle nameKey = globalConst->GetHandledNameString(); PropertyDescriptor nameDesc(thread_, emptyString, false, false, true); JSTaggedValue::DefinePropertyOrThrow(thread_, JSHandle::Cast(function), nameKey, nameDesc); return intlBoundFunc; } JSHandle ObjectFactory::NewJSProxyRevocFunction(const JSHandle &proxy, const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); JSHandle dynclass = JSHandle::Cast(env->GetProxyRevocFunctionClass()); JSHandle revocFunction = JSHandle::Cast(NewJSObject(dynclass)); revocFunction->SetRevocableProxy(thread_, proxy); JSMethod *target = vm_->GetMethodForNativeFunction(nativeFunc); revocFunction->SetCallTarget(thread_, target); JSHandle function = JSHandle::Cast(revocFunction); JSFunction::InitializeJSFunction(thread_, function, FunctionKind::NORMAL_FUNCTION); JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(0)); JSHandle emptyString = globalConst->GetHandledEmptyString(); JSHandle nameKey = globalConst->GetHandledNameString(); PropertyDescriptor nameDesc(thread_, emptyString, false, false, true); JSTaggedValue::DefinePropertyOrThrow(thread_, JSHandle::Cast(function), nameKey, nameDesc); return revocFunction; } JSHandle ObjectFactory::NewJSAsyncAwaitStatusFunction(const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetAsyncAwaitStatusFunctionClass()); JSHandle awaitFunction = JSHandle::Cast(NewJSObject(dynclass)); JSFunction::InitializeJSFunction(thread_, JSHandle::Cast(awaitFunction)); JSMethod *target = vm_->GetMethodForNativeFunction(nativeFunc); awaitFunction->SetCallTarget(thread_, target); return awaitFunction; } JSHandle ObjectFactory::NewJSGeneratorFunction(JSMethod *method) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetGeneratorFunctionClass()); JSHandle generatorFunc = JSHandle::Cast(NewJSObject(dynclass)); JSFunction::InitializeJSFunction(thread_, generatorFunc, FunctionKind::GENERATOR_FUNCTION); generatorFunc->SetCallTarget(thread_, method); return generatorFunc; } JSHandle ObjectFactory::NewJSGeneratorObject(JSHandle generatorFunction) { JSHandle proto(thread_, JSHandle::Cast(generatorFunction)->GetProtoOrDynClass()); if (!proto->IsECMAObject()) { JSHandle realmHandle = JSObject::GetFunctionRealm(thread_, generatorFunction); proto = realmHandle->GetGeneratorPrototype(); } JSHandle dynclass = NewEcmaDynClass(JSGeneratorObject::SIZE, JSType::JS_GENERATOR_OBJECT, proto); JSHandle generatorObject = JSHandle::Cast(NewJSObject(dynclass)); return generatorObject; } JSHandle ObjectFactory::NewAsyncFunction(JSMethod *method) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetAsyncFunctionClass()); JSHandle asyncFunction = JSHandle::Cast(NewJSObject(dynclass)); JSFunction::InitializeJSFunction(thread_, JSHandle::Cast(asyncFunction)); asyncFunction->SetCallTarget(thread_, method); return asyncFunction; } JSHandle ObjectFactory::NewJSAsyncFuncObject() { JSHandle env = vm_->GetGlobalEnv(); JSHandle proto = env->GetInitialGenerator(); JSHandle dynclass = NewEcmaDynClass(JSAsyncFuncObject::SIZE, JSType::JS_ASYNC_FUNC_OBJECT, proto); JSHandle asyncFuncObject = JSHandle::Cast(NewJSObject(dynclass)); return asyncFuncObject; } JSHandle ObjectFactory::NewCompletionRecord(CompletionRecordType type, JSHandle value) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetCompletionRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetType(type); obj->SetValue(thread_, value); return obj; } JSHandle ObjectFactory::NewGeneratorContext() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetGeneratorContextClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetRegsArray(thread_, JSTaggedValue::Undefined()); obj->SetMethod(thread_, JSTaggedValue::Undefined()); obj->SetAcc(thread_, JSTaggedValue::Undefined()); obj->SetGeneratorObject(thread_, JSTaggedValue::Undefined()); obj->SetLexicalEnv(thread_, JSTaggedValue::Undefined()); obj->SetNRegs(0); obj->SetBCOffset(0); return obj; } JSHandle ObjectFactory::NewJSPrimitiveRef(const JSHandle &function, const JSHandle &object) { JSHandle obj(NewJSObjectByConstructor(function, JSHandle(function))); obj->SetValue(thread_, object); JSHandle env = vm_->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); if (function.GetTaggedValue() == env->GetStringFunction().GetTaggedValue()) { JSHandle lengthStr = globalConst->GetHandledLengthString(); int32_t length = EcmaString::Cast(object.GetTaggedValue().GetTaggedObject())->GetLength(); PropertyDescriptor desc(thread_, JSHandle(thread_, JSTaggedValue(length)), false, false, false); JSTaggedValue::DefinePropertyOrThrow(thread_, JSHandle(obj), lengthStr, desc); } return obj; } JSHandle ObjectFactory::NewJSPrimitiveRef(PrimitiveType type, const JSHandle &object) { ObjectFactory *factory = vm_->GetFactory(); JSHandle env = vm_->GetGlobalEnv(); JSHandle function; switch (type) { case PrimitiveType::PRIMITIVE_NUMBER: function = env->GetNumberFunction(); break; case PrimitiveType::PRIMITIVE_STRING: function = env->GetStringFunction(); break; case PrimitiveType::PRIMITIVE_SYMBOL: function = env->GetSymbolFunction(); break; case PrimitiveType::PRIMITIVE_BOOLEAN: function = env->GetBooleanFunction(); break; default: break; } JSHandle funcHandle(function); return factory->NewJSPrimitiveRef(funcHandle, object); } JSHandle ObjectFactory::NewJSString(const JSHandle &str) { JSHandle env = vm_->GetGlobalEnv(); JSHandle stringFunc = env->GetStringFunction(); JSHandle obj = JSHandle::Cast(NewJSObjectByConstructor(JSHandle(stringFunc), stringFunc)); obj->SetValue(thread_, str); return obj; } JSHandle ObjectFactory::NewGlobalEnv(JSHClass *globalEnvClass) { NewObjectHook(); // Note: Global env must be allocated in non-movable heap, since its getters will directly return // the offsets of the properties as the address of Handles. TaggedObject *header = heapHelper_.AllocateNonMovableOrHugeObject(globalEnvClass); InitObjectFields(header); return JSHandle(thread_, GlobalEnv::Cast(header)); } JSHandle ObjectFactory::NewLexicalEnv(int numSlots) { NewObjectHook(); size_t size = LexicalEnv::ComputeSize(numSlots); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetEnvClass().GetTaggedObject()), size); JSHandle array(thread_, header); array->InitializeWithSpecialValue(JSTaggedValue::Undefined(), numSlots + LexicalEnv::RESERVED_ENV_LENGTH); return array; } JSHandle ObjectFactory::NewJSSymbol() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetSymbolClass().GetTaggedObject())); JSHandle obj(thread_, JSSymbol::Cast(header)); obj->SetDescription(thread_, JSTaggedValue::Undefined()); obj->SetFlags(0); obj->SetHashField(SymbolTable::Hash(obj.GetTaggedValue())); return obj; } JSHandle ObjectFactory::NewPrivateSymbol() { JSHandle obj = NewJSSymbol(); obj->SetPrivate(thread_); return obj; } JSHandle ObjectFactory::NewPrivateNameSymbol(const JSHandle &name) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetSymbolClass().GetTaggedObject())); JSHandle obj(thread_, JSSymbol::Cast(header)); obj->SetFlags(0); obj->SetPrivateNameSymbol(thread_); obj->SetDescription(thread_, name); obj->SetHashField(SymbolTable::Hash(name.GetTaggedValue())); return obj; } JSHandle ObjectFactory::NewWellKnownSymbol(const JSHandle &name) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetSymbolClass().GetTaggedObject())); JSHandle obj(thread_, JSSymbol::Cast(header)); obj->SetFlags(0); obj->SetWellKnownSymbol(thread_); obj->SetDescription(thread_, name); obj->SetHashField(SymbolTable::Hash(name.GetTaggedValue())); return obj; } JSHandle ObjectFactory::NewPublicSymbol(const JSHandle &name) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetSymbolClass().GetTaggedObject())); JSHandle obj(thread_, JSSymbol::Cast(header)); obj->SetFlags(0); obj->SetDescription(thread_, name); obj->SetHashField(SymbolTable::Hash(name.GetTaggedValue())); return obj; } JSHandle ObjectFactory::NewSymbolWithTable(const JSHandle &name) { JSHandle env = vm_->GetGlobalEnv(); JSHandle tableHandle(env->GetRegisterSymbols()); if (tableHandle->ContainsKey(thread_, name.GetTaggedValue())) { JSTaggedValue objValue = tableHandle->GetSymbol(name.GetTaggedValue()); return JSHandle(thread_, objValue); } JSHandle obj = NewPublicSymbol(name); JSHandle valueHandle(obj); JSHandle keyHandle(name); JSHandle table = SymbolTable::Insert(thread_, tableHandle, keyHandle, valueHandle); env->SetRegisterSymbols(thread_, table); return obj; } JSHandle ObjectFactory::NewPrivateNameSymbolWithChar(const char *description) { JSHandle string = NewFromString(description); return NewPrivateNameSymbol(JSHandle(string)); } JSHandle ObjectFactory::NewWellKnownSymbolWithChar(const char *description) { JSHandle string = NewFromString(description); return NewWellKnownSymbol(JSHandle(string)); } JSHandle ObjectFactory::NewPublicSymbolWithChar(const char *description) { JSHandle string = NewFromString(description); return NewPublicSymbol(JSHandle(string)); } JSHandle ObjectFactory::NewSymbolWithTableWithChar(const char *description) { JSHandle string = NewFromString(description); return NewSymbolWithTable(JSHandle(string)); } JSHandle ObjectFactory::NewAccessorData() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetAccessorDataClass().GetTaggedObject())); JSHandle acc(thread_, AccessorData::Cast(header)); acc->SetGetter(thread_, JSTaggedValue::Undefined()); acc->SetSetter(thread_, JSTaggedValue::Undefined()); return acc; } JSHandle ObjectFactory::NewInternalAccessor(void *setter, void *getter) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateNonMovableOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetInternalAccessorClass().GetTaggedObject())); JSHandle obj(thread_, AccessorData::Cast(header)); if (setter != nullptr) { JSHandle setFunc = NewJSNativePointer(setter, nullptr, nullptr, true); obj->SetSetter(thread_, setFunc.GetTaggedValue()); } else { JSTaggedValue setFunc = JSTaggedValue::Undefined(); obj->SetSetter(thread_, setFunc); ASSERT(!obj->HasSetter()); } JSHandle getFunc = NewJSNativePointer(getter, nullptr, nullptr, true); obj->SetGetter(thread_, getFunc); return obj; } JSHandle ObjectFactory::NewPromiseCapability() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetCapabilityRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetPromise(thread_, JSTaggedValue::Undefined()); obj->SetResolve(thread_, JSTaggedValue::Undefined()); obj->SetReject(thread_, JSTaggedValue::Undefined()); return obj; } JSHandle ObjectFactory::NewPromiseReaction() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetReactionsRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetPromiseCapability(thread_, JSTaggedValue::Undefined()); obj->SetHandler(thread_, JSTaggedValue::Undefined()); obj->SetType(PromiseType::RESOLVE); return obj; } JSHandle ObjectFactory::NewPromiseIteratorRecord(const JSHandle &itor, bool done) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPromiseIteratorRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetIterator(thread_, itor.GetTaggedValue()); obj->SetDone(done); return obj; } JSHandle ObjectFactory::NewMicroJobQueue() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateNonMovableOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetMicroJobQueueClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetPromiseJobQueue(thread_, GetEmptyTaggedQueue().GetTaggedValue()); obj->SetScriptJobQueue(thread_, GetEmptyTaggedQueue().GetTaggedValue()); return obj; } JSHandle ObjectFactory::NewPendingJob(const JSHandle &func, const JSHandle &argv) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPendingJobClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetJob(thread_, func.GetTaggedValue()); obj->SetArguments(thread_, argv.GetTaggedValue()); return obj; } JSHandle ObjectFactory::NewJSProxy(const JSHandle &target, const JSHandle &handler) { NewObjectHook(); TaggedObject *header = nullptr; const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); if (target->IsCallable()) { auto jsProxyCallableClass = JSHClass::Cast(globalConst->GetJSProxyCallableClass().GetTaggedObject()); auto jsProxyConstructClass = JSHClass::Cast(globalConst->GetJSProxyConstructClass().GetTaggedObject()); header = target->IsConstructor() ? heapHelper_.AllocateYoungGenerationOrHugeObject(jsProxyConstructClass) : heapHelper_.AllocateYoungGenerationOrHugeObject(jsProxyCallableClass); } else { header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetJSProxyOrdinaryClass().GetTaggedObject())); } JSHandle proxy(thread_, header); JSMethod *method = nullptr; if (target->IsCallable()) { JSMethod *nativeMethod = vm_->GetMethodForNativeFunction(reinterpret_cast(builtins::BuiltinsGlobal::CallJsProxy)); proxy->SetCallTarget(thread_, nativeMethod); } proxy->SetMethod(method); proxy->SetTarget(thread_, target.GetTaggedValue()); proxy->SetHandler(thread_, handler.GetTaggedValue()); return proxy; } JSHandle ObjectFactory::NewJSRealm() { JSHandle dynClassClassHandle = NewEcmaDynClassClass(nullptr, JSHClass::SIZE, JSType::HCLASS); JSHClass *dynclass = reinterpret_cast(dynClassClassHandle.GetTaggedValue().GetTaggedObject()); dynclass->SetClass(dynclass); JSHandle realmEnvClass = NewEcmaDynClass(*dynClassClassHandle, GlobalEnv::SIZE, JSType::GLOBAL_ENV); JSHandle realmEnvHandle = NewGlobalEnv(*realmEnvClass); realmEnvHandle->SetEmptyArray(thread_, NewEmptyArray()); realmEnvHandle->SetEmptyTaggedQueue(thread_, NewTaggedQueue(0)); auto result = TemplateMap::Create(thread_); realmEnvHandle->SetTemplateMap(thread_, result); Builtins builtins; builtins.Initialize(realmEnvHandle, thread_); JSHandle protoValue = thread_->GlobalConstants()->GetHandledJSRealmClass(); JSHandle dynHandle = NewEcmaDynClass(JSRealm::SIZE, JSType::JS_REALM, protoValue); JSHandle realm(NewJSObject(dynHandle)); realm->SetGlobalEnv(thread_, realmEnvHandle.GetTaggedValue()); JSHandle realmObj = realmEnvHandle->GetJSGlobalObject(); JSHandle realmkey(thread_->GlobalConstants()->GetHandledGlobalString()); PropertyDescriptor realmDesc(thread_, JSHandle::Cast(realmObj), true, false, true); [[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread_, JSHandle::Cast(realm), realmkey, realmDesc); ASSERT_PRINT(status == true, "Realm defineOwnProperty failed"); return realm; } JSHandle ObjectFactory::NewEmptyArray() { NewObjectHook(); auto header = heapHelper_.AllocateNonMovableOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), TaggedArray::SIZE); JSHandle array(thread_, header); array->SetLength(0); return array; } JSHandle ObjectFactory::NewTaggedArray(uint32_t length, JSTaggedValue initVal, bool nonMovable) { if (nonMovable) { return NewTaggedArray(length, initVal, MemSpaceType::NON_MOVABLE); } return NewTaggedArray(length, initVal, MemSpaceType::SEMI_SPACE); } JSHandle ObjectFactory::NewTaggedArray(uint32_t length, JSTaggedValue initVal, MemSpaceType spaceType) { NewObjectHook(); if (length == 0) { return EmptyArray(); } size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); TaggedObject *header = nullptr; JSHClass *arrayClass = JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()); switch (spaceType) { case MemSpaceType::SEMI_SPACE: header = heapHelper_.AllocateYoungGenerationOrHugeObject(arrayClass, size); break; case MemSpaceType::OLD_SPACE: header = heapHelper_.AllocateOldGenerationOrHugeObject(arrayClass, size); break; case MemSpaceType::NON_MOVABLE: header = heapHelper_.AllocateNonMovableOrHugeObject(arrayClass, size); break; default: UNREACHABLE(); } JSHandle array(thread_, header); array->InitializeWithSpecialValue(initVal, length); return array; } JSHandle ObjectFactory::NewTaggedArray(uint32_t length, JSTaggedValue initVal) { NewObjectHook(); if (length == 0) { return EmptyArray(); } size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle array(thread_, header); array->InitializeWithSpecialValue(initVal, length); return array; } JSHandle ObjectFactory::NewDictionaryArray(uint32_t length) { NewObjectHook(); ASSERT(length > 0); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetDictionaryClass().GetTaggedObject()), size); JSHandle array(thread_, header); array->InitializeWithSpecialValue(JSTaggedValue::Undefined(), length); return array; } JSHandle ObjectFactory::ExtendArray(const JSHandle &old, uint32_t length, JSTaggedValue initVal) { ASSERT(length > old->GetLength()); NewObjectHook(); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle newArray(thread_, header); newArray->SetLength(length); uint32_t oldLength = old->GetLength(); for (uint32_t i = 0; i < oldLength; i++) { JSTaggedValue value = old->Get(i); newArray->Set(thread_, i, value); } for (uint32_t i = oldLength; i < length; i++) { newArray->Set(thread_, i, initVal); } return newArray; } JSHandle ObjectFactory::CopyPartArray(const JSHandle &old, uint32_t start, uint32_t end) { ASSERT(start <= end); ASSERT(end <= old->GetLength()); uint32_t newLength = end - start; if (newLength == 0) { return EmptyArray(); } NewObjectHook(); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle newArray(thread_, header); newArray->SetLength(newLength); for (uint32_t i = 0; i < newLength; i++) { JSTaggedValue value = old->Get(i + start); if (value.IsHole()) { break; } newArray->Set(thread_, i, value); } return newArray; } JSHandle ObjectFactory::CopyArray(const JSHandle &old, [[maybe_unused]] uint32_t oldLength, uint32_t newLength, JSTaggedValue initVal) { if (newLength == 0) { return EmptyArray(); } if (newLength > oldLength) { return ExtendArray(old, newLength, initVal); } NewObjectHook(); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle newArray(thread_, header); newArray->SetLength(newLength); for (uint32_t i = 0; i < newLength; i++) { JSTaggedValue value = old->Get(i); newArray->Set(thread_, i, value); } return newArray; } JSHandle ObjectFactory::CreateLayoutInfo(int properties, JSTaggedValue initVal) { int arrayLength = LayoutInfo::ComputeArrayLength(LayoutInfo::ComputeGrowCapacity(properties)); JSHandle layoutInfoHandle = JSHandle::Cast(NewTaggedArray(arrayLength, initVal)); layoutInfoHandle->SetNumberOfElements(thread_, 0); return layoutInfoHandle; } JSHandle ObjectFactory::ExtendLayoutInfo(const JSHandle &old, int properties, JSTaggedValue initVal) { ASSERT(properties > old->NumberOfElements()); int arrayLength = LayoutInfo::ComputeArrayLength(LayoutInfo::ComputeGrowCapacity(properties)); return JSHandle(ExtendArray(JSHandle(old), arrayLength, initVal)); } JSHandle ObjectFactory::CopyLayoutInfo(const JSHandle &old) { int newLength = old->GetLength(); return JSHandle(CopyArray(JSHandle::Cast(old), newLength, newLength)); } JSHandle ObjectFactory::CopyAndReSort(const JSHandle &old, int end, int capacity) { ASSERT(capacity >= end); JSHandle newArr = CreateLayoutInfo(capacity); Span sp(old->GetProperties(), end); int i = 0; for (; i < end; i++) { newArr->AddKey(thread_, i, sp[i].key_, PropertyAttributes(sp[i].attr_)); } return newArr; } JSHandle ObjectFactory::NewConstantPool(uint32_t capacity) { NewObjectHook(); if (capacity == 0) { return JSHandle::Cast(EmptyArray()); } size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), capacity); auto header = heapHelper_.AllocateNonMovableOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle array(thread_, header); array->InitializeWithSpecialValue(JSTaggedValue::Undefined(), capacity); return array; } JSHandle ObjectFactory::NewProgram() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetProgramClass().GetTaggedObject())); JSHandle p(thread_, header); p->SetLocation(thread_, JSTaggedValue::Undefined()); p->SetConstantPool(thread_, JSTaggedValue::Undefined()); p->SetMainFunction(thread_, JSTaggedValue::Undefined()); p->SetMethodsData(nullptr); return p; } JSHandle ObjectFactory::NewEmptyEcmaModule() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetEcmaModuleClass().GetTaggedObject())); JSHandle module(thread_, header); module->SetNameDictionary(thread_, JSTaggedValue::Undefined()); return module; } JSHandle ObjectFactory::GetEmptyString() const { return JSHandle(thread_->GlobalConstants()->GetHandledEmptyString()); } JSHandle ObjectFactory::EmptyArray() const { JSHandle env = vm_->GetGlobalEnv(); return JSHandle(env->GetEmptyArray()); } JSHandle ObjectFactory::GetStringFromStringTable(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const { NewObjectHook(); if (utf8Len == 0) { return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); return JSHandle(thread_, stringTable->GetOrInternString(utf8Data, utf8Len, canBeCompress)); } JSHandle ObjectFactory::GetStringFromStringTable(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) const { NewObjectHook(); if (utf16Len == 0) { return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); return JSHandle(thread_, stringTable->GetOrInternString(utf16Data, utf16Len, canBeCompress)); } JSHandle ObjectFactory::GetStringFromStringTable(EcmaString *string) const { ASSERT(string != nullptr); if (string->GetLength() == 0) { return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); return JSHandle(thread_, stringTable->GetOrInternString(string)); } // NB! don't do special case for C0 80, it means '\u0000', so don't convert to UTF-8 EcmaString *ObjectFactory::GetRawStringFromStringTable(const uint8_t *mutf8Data, uint32_t utf16Len, bool canBeCompressed) const { NewObjectHook(); if (UNLIKELY(utf16Len == 0)) { return *GetEmptyString(); } if (canBeCompressed) { return EcmaString::Cast(vm_->GetEcmaStringTable()->GetOrInternString(mutf8Data, utf16Len, true)); } CVector utf16Data(utf16Len); auto len = utf::ConvertRegionMUtf8ToUtf16(mutf8Data, utf16Data.data(), utf::Mutf8Size(mutf8Data), utf16Len, 0); return EcmaString::Cast(vm_->GetEcmaStringTable()->GetOrInternString(utf16Data.data(), len, false)); } JSHandle ObjectFactory::NewPropertyBox(const JSHandle &value) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPropertyBoxClass().GetTaggedObject())); JSHandle box(thread_, header); box->SetValue(thread_, value); return box; } JSHandle ObjectFactory::NewProtoChangeMarker() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetProtoChangeMarkerClass().GetTaggedObject())); JSHandle marker(thread_, header); marker->ClearBitField(); return marker; } JSHandle ObjectFactory::NewProtoChangeDetails() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetProtoChangeDetailsClass().GetTaggedObject())); JSHandle protoInfo(thread_, header); protoInfo->SetChangeListener(thread_, JSTaggedValue::Undefined()); protoInfo->SetRegisterIndex(ProtoChangeDetails::UNREGISTERED); return protoInfo; } JSHandle ObjectFactory::NewProfileTypeInfo(uint32_t length) { NewObjectHook(); ASSERT(length > 0); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); auto header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), size); JSHandle array(thread_, header); array->InitializeWithSpecialValue(JSTaggedValue::Undefined(), length); return array; } // static void ObjectFactory::NewObjectHook() const { #ifndef NDEBUG if (vm_->GetJSOptions().IsEnableForceGC() && vm_->IsInitialized()) { if (vm_->GetJSOptions().IsForceFullGC()) { vm_->CollectGarbage(TriggerGCType::SEMI_GC); vm_->CollectGarbage(TriggerGCType::OLD_GC); vm_->CollectGarbage(TriggerGCType::FULL_GC); } else { vm_->CollectGarbage(TriggerGCType::SEMI_GC); vm_->CollectGarbage(TriggerGCType::OLD_GC); } } #endif } JSHandle ObjectFactory::NewTaggedQueue(uint32_t length) { uint32_t queueLength = TaggedQueue::QueueToArrayIndex(length); auto queue = JSHandle::Cast(NewTaggedArray(queueLength, JSTaggedValue::Hole())); queue->SetStart(thread_, JSTaggedValue(0)); // equal to 0 when add 1. queue->SetEnd(thread_, JSTaggedValue(0)); queue->SetCapacity(thread_, JSTaggedValue(length)); return queue; } JSHandle ObjectFactory::GetEmptyTaggedQueue() const { JSHandle env = vm_->GetGlobalEnv(); return JSHandle(env->GetEmptyTaggedQueue()); } JSHandle ObjectFactory::NewJSSetIterator(const JSHandle &set, IterationKind kind) { JSHandle env = vm_->GetGlobalEnv(); JSHandle protoValue = env->GetSetIteratorPrototype(); JSHandle dynHandle = NewEcmaDynClass(JSSetIterator::SIZE, JSType::JS_SET_ITERATOR, protoValue); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedSet(thread_, set->GetLinkedSet()); iter->SetNextIndex(0); iter->SetIterationKind(kind); return iter; } JSHandle ObjectFactory::NewJSMapIterator(const JSHandle &map, IterationKind kind) { JSHandle env = vm_->GetGlobalEnv(); JSHandle protoValue = env->GetMapIteratorPrototype(); JSHandle dynHandle = NewEcmaDynClass(JSMapIterator::SIZE, JSType::JS_MAP_ITERATOR, protoValue); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedMap(thread_, map->GetLinkedMap()); iter->SetNextIndex(0); iter->SetIterationKind(kind); return iter; } JSHandle ObjectFactory::NewJSArrayIterator(const JSHandle &array, IterationKind kind) { JSHandle env = vm_->GetGlobalEnv(); JSHandle protoValue = env->GetArrayIteratorPrototype(); JSHandle dynHandle = NewEcmaDynClass(JSArrayIterator::SIZE, JSType::JS_ARRAY_ITERATOR, protoValue); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedArray(thread_, array); iter->SetNextIndex(0); iter->SetIterationKind(kind); return iter; } JSHandle ObjectFactory::CreateJSPromiseReactionsFunction(const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetPromiseReactionFunctionClass()); JSHandle reactionsFunction = JSHandle::Cast(NewJSObject(dynclass)); reactionsFunction->SetPromise(thread_, JSTaggedValue::Hole()); reactionsFunction->SetAlreadyResolved(thread_, JSTaggedValue::Hole()); JSMethod *method = vm_->GetMethodForNativeFunction(nativeFunc); reactionsFunction->SetCallTarget(thread_, method); JSHandle function = JSHandle::Cast(reactionsFunction); JSFunction::InitializeJSFunction(thread_, function); JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(1)); return reactionsFunction; } JSHandle ObjectFactory::CreateJSPromiseExecutorFunction(const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetPromiseExecutorFunctionClass()); JSHandle executorFunction = JSHandle::Cast(NewJSObject(dynclass)); executorFunction->SetCapability(thread_, JSTaggedValue::Hole()); JSMethod *method = vm_->GetMethodForNativeFunction(nativeFunc); executorFunction->SetCallTarget(thread_, method); executorFunction->SetCapability(thread_, JSTaggedValue::Undefined()); JSHandle function = JSHandle::Cast(executorFunction); JSFunction::InitializeJSFunction(thread_, function, FunctionKind::NORMAL_FUNCTION); JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(FunctionLength::TWO)); return executorFunction; } JSHandle ObjectFactory::NewJSPromiseAllResolveElementFunction( const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetPromiseAllResolveElementFunctionClass()); JSHandle function = JSHandle::Cast(NewJSObject(dynclass)); JSFunction::InitializeJSFunction(thread_, JSHandle::Cast(function)); JSMethod *method = vm_->GetMethodForNativeFunction(nativeFunc); function->SetCallTarget(thread_, method); JSFunction::SetFunctionLength(thread_, JSHandle::Cast(function), JSTaggedValue(1)); return function; } EcmaString *ObjectFactory::InternString(const JSHandle &key) { EcmaString *str = EcmaString::Cast(key->GetTaggedObject()); if (str->IsInternString()) { return str; } EcmaStringTable *stringTable = vm_->GetEcmaStringTable(); return stringTable->GetOrInternString(str); } JSHandle ObjectFactory::NewTransitionHandler() { NewObjectHook(); TransitionHandler *handler = TransitionHandler::Cast(heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetTransitionHandlerClass().GetTaggedObject()))); return JSHandle(thread_, handler); } JSHandle ObjectFactory::NewPrototypeHandler() { NewObjectHook(); PrototypeHandler *header = PrototypeHandler::Cast(heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPrototypeHandlerClass().GetTaggedObject()))); JSHandle handler(thread_, header); handler->SetHandlerInfo(thread_, JSTaggedValue::Undefined()); handler->SetProtoCell(thread_, JSTaggedValue::Undefined()); handler->SetHolder(thread_, JSTaggedValue::Undefined()); return handler; } JSHandle ObjectFactory::NewPromiseRecord() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPromiseRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetValue(thread_, JSTaggedValue::Undefined()); return obj; } JSHandle ObjectFactory::NewResolvingFunctionsRecord() { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetPromiseResolvingFunctionsRecordClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->SetResolveFunction(thread_, JSTaggedValue::Undefined()); obj->SetRejectFunction(thread_, JSTaggedValue::Undefined()); return obj; } JSHandle ObjectFactory::CreateObjectClass(const JSHandle &properties, size_t length) { JSHandle env = vm_->GetGlobalEnv(); JSHandle proto = env->GetObjectFunctionPrototype(); uint32_t fieldOrder = 0; JSMutableHandle key(thread_, JSTaggedValue::Undefined()); JSHandle layoutInfoHandle = CreateLayoutInfo(length); while (fieldOrder < length) { key.Update(properties->Get(fieldOrder * 2)); // 2: Meaning to double ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); PropertyAttributes attributes = PropertyAttributes::Default(); if (properties->Get(fieldOrder * 2 + 1).IsAccessor()) { // 2: Meaning to double attributes.SetIsAccessor(true); } attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::MIXED); attributes.SetOffset(fieldOrder); layoutInfoHandle->AddKey(thread_, fieldOrder, key.GetTaggedValue(), attributes); fieldOrder++; } ASSERT(fieldOrder <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES); JSHandle objClass = NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, fieldOrder); objClass->SetPrototype(thread_, proto.GetTaggedValue()); { objClass->SetExtensible(true); objClass->SetIsLiteral(true); objClass->SetLayout(thread_, layoutInfoHandle); objClass->SetNumberOfProps(fieldOrder); } return objClass; } JSHandle ObjectFactory::NewJSObjectByClass(const JSHandle &properties, size_t length) { JSHandle dynclass = CreateObjectClass(properties, length); JSHandle obj = NewJSObject(dynclass); return obj; } JSHandle ObjectFactory::NewEmptyJSObject() { JSHandle env = vm_->GetGlobalEnv(); JSHandle builtinObj = env->GetObjectFunction(); return NewJSObjectByConstructor(JSHandle(builtinObj), builtinObj); } EcmaString *ObjectFactory::ResolveString(uint32_t stringId) { JSMethod *caller = InterpretedFrameHandler(thread_).GetMethod(); auto *pf = caller->GetPandaFile(); auto id = panda_file::File::EntityId(stringId); auto foundStr = pf->GetStringData(id); return GetRawStringFromStringTable(foundStr.data, foundStr.utf16_length, foundStr.is_ascii); } uintptr_t ObjectFactory::NewSpaceBySnapShotAllocator(size_t size) { NewObjectHook(); return heapHelper_.AllocateSnapShotSpace(size); } JSHandle ObjectFactory::NewMachineCodeObject(size_t length, const uint8_t *data) { NewObjectHook(); TaggedObject *obj = heapHelper_.AllocateMachineCodeSpaceObject(JSHClass::Cast( thread_->GlobalConstants()->GetMachineCodeClass().GetTaggedObject()), length + MachineCode::SIZE); MachineCode *code = MachineCode::Cast(obj); code->SetInstructionSizeInBytes(static_cast(length)); if (data != nullptr) { code->SetData(data, length); } JSHandle codeObj(thread_, code); return codeObj; } JSHandle ObjectFactory::NewClassInfoExtractor(JSMethod *ctorMethod) { NewObjectHook(); TaggedObject *header = heapHelper_.AllocateYoungGenerationOrHugeObject( JSHClass::Cast(thread_->GlobalConstants()->GetClassInfoExtractorHClass().GetTaggedObject())); JSHandle obj(thread_, header); obj->ClearBitField(); obj->SetConstructorMethod(ctorMethod); JSHandle emptyArray = EmptyArray(); obj->SetPrototypeHClass(thread_, JSTaggedValue::Undefined()); obj->SetNonStaticKeys(thread_, emptyArray, SKIP_BARRIER); obj->SetNonStaticProperties(thread_, emptyArray, SKIP_BARRIER); obj->SetNonStaticElements(thread_, emptyArray, SKIP_BARRIER); obj->SetConstructorHClass(thread_, JSTaggedValue::Undefined()); obj->SetStaticKeys(thread_, emptyArray, SKIP_BARRIER); obj->SetStaticProperties(thread_, emptyArray, SKIP_BARRIER); obj->SetStaticElements(thread_, emptyArray, SKIP_BARRIER); return obj; } // ----------------------------------- new string ---------------------------------------- JSHandle ObjectFactory::NewFromString(const CString &data) { auto utf8Data = reinterpret_cast(data.c_str()); bool canBeCompress = EcmaString::CanBeCompressed(utf8Data, data.length()); return GetStringFromStringTable(utf8Data, data.length(), canBeCompress); } JSHandle ObjectFactory::NewFromCanBeCompressString(const CString &data) { auto utf8Data = reinterpret_cast(data.c_str()); ASSERT(EcmaString::CanBeCompressed(utf8Data, data.length())); return GetStringFromStringTable(utf8Data, data.length(), true); } JSHandle ObjectFactory::NewFromStdString(const std::string &data) { auto utf8Data = reinterpret_cast(data.c_str()); bool canBeCompress = EcmaString::CanBeCompressed(utf8Data, data.length()); return GetStringFromStringTable(utf8Data, data.size(), canBeCompress); } JSHandle ObjectFactory::NewFromStdStringUnCheck(const std::string &data, bool canBeCompress) { auto utf8Data = reinterpret_cast(data.c_str()); return GetStringFromStringTable(utf8Data, data.size(), canBeCompress); } JSHandle ObjectFactory::NewFromUtf8(const uint8_t *utf8Data, uint32_t utf8Len) { bool canBeCompress = EcmaString::CanBeCompressed(utf8Data, utf8Len); return GetStringFromStringTable(utf8Data, utf8Len, canBeCompress); } JSHandle ObjectFactory::NewFromUtf8UnCheck(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) { return GetStringFromStringTable(utf8Data, utf8Len, canBeCompress); } JSHandle ObjectFactory::NewFromUtf16(const uint16_t *utf16Data, uint32_t utf16Len) { bool canBeCompress = EcmaString::CanBeCompressed(utf16Data, utf16Len); return GetStringFromStringTable(utf16Data, utf16Len, canBeCompress); } JSHandle ObjectFactory::NewFromUtf16UnCheck(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) { return GetStringFromStringTable(utf16Data, utf16Len, canBeCompress); } JSHandle ObjectFactory::NewFromUtf8Literal(const uint8_t *utf8Data, uint32_t utf8Len) { NewObjectHook(); bool canBeCompress = EcmaString::CanBeCompressed(utf8Data, utf8Len); return JSHandle(thread_, EcmaString::CreateFromUtf8(utf8Data, utf8Len, vm_, canBeCompress)); } JSHandle ObjectFactory::NewFromUtf8LiteralUnCheck(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) { NewObjectHook(); return JSHandle(thread_, EcmaString::CreateFromUtf8(utf8Data, utf8Len, vm_, canBeCompress)); } JSHandle ObjectFactory::NewFromUtf16Literal(const uint16_t *utf16Data, uint32_t utf16Len) { NewObjectHook(); bool canBeCompress = EcmaString::CanBeCompressed(utf16Data, utf16Len); return JSHandle(thread_, EcmaString::CreateFromUtf16(utf16Data, utf16Len, vm_, canBeCompress)); } JSHandle ObjectFactory::NewFromUtf16LiteralUnCheck(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) { NewObjectHook(); return JSHandle(thread_, EcmaString::CreateFromUtf16(utf16Data, utf16Len, vm_, canBeCompress)); } JSHandle ObjectFactory::NewFromString(EcmaString *str) { return GetStringFromStringTable(str); } JSHandle ObjectFactory::ConcatFromString(const JSHandle &firstString, const JSHandle &secondString) { if (firstString->GetLength() == 0) { return secondString; } if (secondString->GetLength() == 0) { return firstString; } return GetStringFromStringTable(firstString, secondString); } JSHandle ObjectFactory::GetStringFromStringTable(const JSHandle &firstString, const JSHandle &secondString) { auto stringTable = vm_->GetEcmaStringTable(); return JSHandle(thread_, stringTable->GetOrInternString(firstString, secondString)); } JSHandle ObjectFactory::NewJSAPIArrayList(uint32_t capacity) { NewObjectHook(); JSHandle builtinObj(thread_, thread_->GlobalConstants()->GetArrayListFunction()); JSHandle obj = JSHandle(NewJSObjectByConstructor(JSHandle(builtinObj), builtinObj)); ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory(); obj->SetElements(thread_, factory->NewTaggedArray(capacity)); return obj; } JSHandle ObjectFactory::NewJSAPIArrayListIterator(const JSHandle &arrayList) { NewObjectHook(); JSHandle protoValue(thread_, thread_->GlobalConstants()->GetArrayListIteratorPrototype()); JSHandle dynHandle = NewEcmaDynClass(JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR, protoValue); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedArrayList(thread_, arrayList); iter->SetNextIndex(thread_, JSTaggedValue(0)); return iter; } JSHandle ObjectFactory::NewJSAPITreeMapIterator(const JSHandle &map, IterationKind kind) { NewObjectHook(); JSHandle proto(thread_, thread_->GlobalConstants()->GetTreeMapIteratorPrototype()); JSHandle dynHandle = NewEcmaDynClass(JSAPITreeMapIterator::SIZE, JSType::JS_API_TREEMAP_ITERATOR, proto); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedMap(thread_, map); iter->SetNextIndex(thread_, JSTaggedValue(0)); iter->SetIterationKind(thread_, JSTaggedValue(static_cast(kind))); JSHandle tmap(thread_, map->GetTreeMap()); JSHandle entries = TaggedTreeMap::GetArrayFromMap(thread_, tmap); iter->SetEntries(thread_, entries); return iter; } JSHandle ObjectFactory::NewJSAPITreeSetIterator(const JSHandle &set, IterationKind kind) { NewObjectHook(); JSHandle proto(thread_, thread_->GlobalConstants()->GetTreeSetIteratorPrototype()); JSHandle dynHandle = NewEcmaDynClass(JSAPITreeSetIterator::SIZE, JSType::JS_API_TREESET_ITERATOR, proto); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); iter->SetIteratedSet(thread_, set); iter->SetNextIndex(thread_, JSTaggedValue(0)); iter->SetIterationKind(thread_, JSTaggedValue(static_cast(kind))); JSHandle tset(thread_, set->GetTreeSet()); JSHandle entries = TaggedTreeSet::GetArrayFromSet(thread_, tset); iter->SetEntries(thread_, entries); return iter; } } // namespace panda::ecmascript