/* * 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 "js_function.h" #include "ecmascript/base/error_type.h" #include "ecmascript/class_info_extractor.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_runtime_call_info.h" #include "ecmascript/global_env.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_proxy.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" namespace panda::ecmascript { void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle &func, FunctionKind kind, bool strict) { FunctionMode thisMode; if (IsArrowFunction(kind)) { thisMode = FunctionMode::LEXICAL; } else if (strict) { thisMode = FunctionMode::STRICT; } else { thisMode = FunctionMode::GLOBAL; } func->SetProtoOrDynClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER); func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetConstantPool(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetProfileTypeInfo(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetFunctionExtraInfo(thread, JSTaggedValue::Undefined()); func->SetFunctionKind(kind); func->SetStrict(strict); func->SetThisMode(thisMode); func->SetResolved(false); auto globalConst = thread->GlobalConstants(); if (HasPrototype(kind)) { JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION) { func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); accessor = globalConst->GetHandledFunctionNameAccessor(); func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); } else if (!JSFunction::IsClassConstructor(kind)) { // class ctor do nothing PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false); [[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle(func), globalConst->GetHandledPrototypeString(), desc); ASSERT(success); } } else if (HasAccessor(kind)) { JSHandle accessor = globalConst->GetHandledFunctionNameAccessor(); func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); } } JSHandle JSFunction::NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory, const JSHandle &func) { JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle objFun = env->GetObjectFunction(); JSHandle funPro = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); func->SetFunctionPrototype(thread, funPro.GetTaggedValue()); // set "constructor" in prototype JSHandle constructorKey = globalConst->GetHandledConstructorString(); PropertyDescriptor descriptor(thread, JSHandle::Cast(func), true, false, true); JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor); return funPro; } JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle &fun) { JSTaggedValue protoOrDyn(fun->GetProtoOrDynClass()); if (protoOrDyn.IsJSHClass()) { return reinterpret_cast(protoOrDyn.GetTaggedObject()); } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle proto; if (!fun->HasFunctionPrototype()) { proto = JSHandle::Cast(NewJSFunctionPrototype(thread, factory, fun)); } else { proto = JSHandle(thread, fun->GetProtoOrDynClass()); } JSHandle dynclass = factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, proto); fun->SetProtoOrDynClass(thread, dynclass); return *dynclass; } JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle &self) { JSHandle func = JSHandle::Cast(self); if (!func->HasFunctionPrototype()) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); NewJSFunctionPrototype(thread, factory, func); } return JSFunction::Cast(*self)->GetFunctionPrototype(); } bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle &self, const JSHandle &value, [[maybe_unused]] bool mayThrow) { JSHandle func(self); JSTaggedValue protoOrDyn = func->GetProtoOrDynClass(); if (protoOrDyn.IsJSHClass()) { // need transtion JSHandle dynclass(thread, protoOrDyn); JSHandle newDynclass = JSHClass::TransitionProto(thread, dynclass, value); if (value->IsECMAObject()) { JSObject::Cast(value->GetTaggedObject())->GetJSHClass()->SetIsPrototype(true); } func->SetProtoOrDynClass(thread, newDynclass); } else { func->SetFunctionPrototype(thread, value.GetTaggedValue()); } return true; } JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle &self) { JSMethod *target = JSHandle::Cast(self)->GetCallTarget(); if (target->GetPandaFile() == nullptr) { return JSTaggedValue::Undefined(); } std::string funcName = target->ParseFunctionName(); if (funcName.empty()) { return thread->GlobalConstants()->GetEmptyString(); } if (JSHandle::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) { funcName.insert(0, "get "); } if (JSHandle::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) { funcName.insert(0, "set "); } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); return factory->NewFromStdString(funcName).GetTaggedValue(); } bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle &constructor, const JSHandle &obj) { // 1. If IsCallable(C) is false, return false. if (!constructor->IsCallable()) { return false; } // 2. If C has a [[BoundTargetFunction]] internal slot, then // a. Let BC be the value of C's [[BoundTargetFunction]] internal slot. // b. Return InstanceofOperator(O,BC) (see 12.9.4). if (constructor->IsBoundFunction()) { JSHandle boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject())); JSTaggedValue boundTarget = boundFunction->GetBoundTarget(); return JSObject::InstanceOf(thread, obj, JSHandle(thread, boundTarget)); } // 3. If Type(O) is not Object, return false if (!obj->IsECMAObject()) { return false; } // 4. Let P be Get(C, "prototype"). const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle constructorPrototype = JSTaggedValue::GetProperty(thread, constructor, globalConst->GetHandledPrototypeString()).GetValue(); // 5. ReturnIfAbrupt(P). // no throw exception, so needn't return RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); // 6. If Type(P) is not Object, throw a TypeError exception. if (!constructorPrototype->IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false); } // 7. Repeat // a.Let O be O.[[GetPrototypeOf]](). // b.ReturnIfAbrupt(O). // c.If O is null, return false. // d.If SameValue(P, O) is true, return true. JSTaggedValue objPrototype = obj.GetTaggedValue(); while (!objPrototype.IsNull()) { if (JSTaggedValue::SameValue(objPrototype, constructorPrototype.GetTaggedValue())) { return true; } objPrototype = JSObject::Cast(objPrototype)->GetPrototype(thread); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); } return false; } bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle &func, const JSHandle &proto, bool writable) { ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined"); ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type"); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle constructorKey = globalConst->GetHandledConstructorString(); ASSERT_PRINT(func->GetProtoOrDynClass().IsHole() && func->IsExtensible(), "function doesn't has proto_type property and is extensible object"); ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle(func), constructorKey), "function must have constructor"); // proto.constructor = func bool status = false; if (proto->IsUndefined()) { // Let prototype be ObjectCreate(%ObjectPrototype%). JSHandle objPrototype = env->GetObjectFunctionPrototype(); PropertyDescriptor constructorDesc(thread, JSHandle::Cast(func), writable, false, true); status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc); } else { PropertyDescriptor constructorDesc(thread, JSHandle::Cast(func), writable, false, true); status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc); } ASSERT_PRINT(status, "DefineProperty construct failed"); // func.prototype = proto // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}). func->SetFunctionPrototype(thread, proto.GetTaggedValue()); ASSERT_PRINT(status, "DefineProperty proto_type failed"); return status; } JSTaggedValue JSFunction::Call(JSThread *thread, const JSHandle &func, const JSHandle &thisArg, uint32_t argc, const JSTaggedType argv[]) { // 1. ReturnIfAbrupt(F). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 2. If argumentsList was not passed, let argumentsList be a new empty List. // 3. If IsCallable(F) is false, throw a TypeError exception. if (!func->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); } if (func->IsJSFunction()) { return JSFunction::CallInternal(thread, JSHandle(func), thisArg, argc, argv); } if (func->IsBoundFunction()) { return JSBoundFunction::CallInternal(thread, JSHandle(func)); } if (func->IsJSProxy()) { return JSProxy::CallInternal(thread, JSHandle(func), thisArg, argc, argv); } THROW_TYPE_ERROR_AND_RETURN(thread, "Call NonCallable", JSTaggedValue::Exception()); } JSTaggedValue JSFunction::Construct(JSThread *thread, const JSHandle &func, uint32_t argc, const JSTaggedType argv[], const JSHandle &newTarget) { JSMutableHandle target(thread, newTarget.GetTaggedValue()); if (target->IsUndefined()) { target.Update(func.GetTaggedValue()); } if (!(func->IsConstructor() && target->IsConstructor())) { THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception()); } if (func->IsJSFunction()) { return JSFunction::ConstructInternal(thread, JSHandle(func), argc, argv, target); } if (func->IsBoundFunction()) { return JSBoundFunction::ConstructInternal(thread, JSHandle(func), target); } if (func->IsJSProxy()) { return JSProxy::ConstructInternal(thread, JSHandle(func), argc, argv, target); } THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor NonConstructor", JSTaggedValue::Exception()); } JSTaggedValue JSFunction::Invoke(JSThread *thread, const JSHandle &thisArg, const JSHandle &key, uint32_t argc, const JSTaggedType argv[]) { ASSERT(JSTaggedValue::IsPropertyKey(key)); JSHandle func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue()); return JSFunction::Call(thread, func, thisArg, argc, argv); } // [[Call]] JSTaggedValue JSFunction::CallInternal(JSThread *thread, const JSHandle &func, const JSHandle &thisArg, uint32_t argc, const JSTaggedType argv[]) { if (!func->IsBuiltinsConstructor() && func->IsClassConstructor()) { THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception()); } CallParams params; params.callTarget = ECMAObject::Cast(*func); params.newTarget = JSTaggedValue::VALUE_UNDEFINED; params.thisArg = thisArg.GetTaggedType(); params.argc = argc; params.argv = argv; return EcmaInterpreter::Execute(thread, params); } // [[Construct]] JSTaggedValue JSFunction::ConstructInternal(JSThread *thread, const JSHandle &func, uint32_t argc, const JSTaggedType argv[], const JSHandle &newTarget) { ASSERT(newTarget->IsECMAObject()); if (!func->IsConstructor()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception()); } JSHandle obj(thread, JSTaggedValue::Undefined()); if (!func->IsBuiltinsConstructor() && func->IsBase()) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); obj = JSHandle(factory->NewJSObjectByConstructor(func, newTarget)); } CallParams params; params.callTarget = ECMAObject::Cast(*func); params.newTarget = newTarget.GetTaggedType(); params.thisArg = obj.GetTaggedType(); params.argc = argc; params.argv = argv; JSTaggedValue resultValue = EcmaInterpreter::Execute(thread, params); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 9.3.2 [[Construct]] (argumentsList, newTarget) if (func->IsBuiltinsConstructor() || resultValue.IsECMAObject()) { return resultValue; } if (func->IsBase()) { return obj.GetTaggedValue(); } // derived ctor(sub class) return the obj which created by base ctor(parent class) if (func->IsDerivedConstructor()) { return resultValue; } if (!resultValue.IsUndefined()) { THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception()); } return obj.GetTaggedValue(); } JSHandle JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle &func) { JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); return JSObject::GetProperty(thread, JSHandle(func), nameKey).GetValue(); } bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle &func, const JSHandle &name, const JSHandle &prefix) { ASSERT_PRINT(func->IsExtensible(), "Function must be extensible"); ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol"); bool needPrefix = false; ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); if (!prefix->IsUndefined()) { ASSERT_PRINT(prefix->IsString(), "prefix must be string"); needPrefix = true; } // If Type(name) is Symbol, then // Let description be name’s [[Description]] value. // If description is undefined, let name be the empty String. // Else, let name be the concatenation of "[", description, and "]". JSHandle functionName; if (name->IsSymbol()) { JSTaggedValue description = JSHandle::Cast(name)->GetDescription(); JSHandle descriptionHandle(thread, description); if (description.IsUndefined()) { functionName = factory->GetEmptyString(); } else { JSHandle leftBrackets = factory->NewFromCanBeCompressString("["); JSHandle rightBrackets = factory->NewFromCanBeCompressString("]"); functionName = factory->ConcatFromString(leftBrackets, descriptionHandle); functionName = factory->ConcatFromString(functionName, rightBrackets); } } else { functionName = JSHandle::Cast(name); } EcmaString *newString; if (needPrefix) { JSHandle handlePrefixString = JSTaggedValue::ToString(thread, prefix); JSHandle spaceString(factory->NewFromCanBeCompressString(" ")); JSHandle concatString = factory->ConcatFromString(handlePrefixString, spaceString); newString = *factory->ConcatFromString(concatString, functionName); } else { newString = *functionName; } JSHandle nameHandle(thread, newString); JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); PropertyDescriptor nameDesc(thread, nameHandle, false, false, true); JSHandle funcHandle(func); return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc); } bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle &func, JSTaggedValue length, bool cfg) { ASSERT_PRINT(func->IsExtensible(), "Function must be extensible"); ASSERT_PRINT(length.IsInteger(), "length must be integer"); JSHandle lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString(); ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle(thread, length), JSHandle(thread, JSTaggedValue(0))), "length must be non negtive integer"); PropertyDescriptor lengthDesc(thread, JSHandle(thread, length), false, false, cfg); JSHandle funcHandle(func); return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc); } JSTaggedValue JSBoundFunction::CallInternal(JSThread *thread, const JSHandle &func) { JSHandle target(thread, func->GetBoundTarget()); JSHandle boundThis(thread, func->GetBoundThis()); InternalCallParams *params = thread->GetInternalCallParams(); params->MakeBoundArgv(thread, func); return JSFunction::Call(thread, target, boundThis, params->GetLength(), params->GetArgv()); } // 9.4.1.2[[Construct]](argumentsList, newTarget) JSTaggedValue JSBoundFunction::ConstructInternal(JSThread *thread, const JSHandle &func, const JSHandle &newTarget) { JSHandle target(thread, func->GetBoundTarget()); ASSERT(target->IsConstructor()); JSMutableHandle newTargetMutable(thread, newTarget.GetTaggedValue()); if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) { newTargetMutable.Update(target.GetTaggedValue()); } InternalCallParams *params = thread->GetInternalCallParams(); params->MakeBoundArgv(thread, func); return JSFunction::Construct(thread, target, params->GetLength(), params->GetArgv(), newTargetMutable); } void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle &revoker) { // 1.Let p be the value of F’s [[RevocableProxy]] internal slot. JSTaggedValue proxy = revoker->GetRevocableProxy(); // 2.If p is null, return undefined. if (proxy.IsNull()) { return; } // 3.Set the value of F’s [[RevocableProxy]] internal slot to null. revoker->SetRevocableProxy(thread, JSTaggedValue::Null()); // 4.Assert: p is a Proxy object. ASSERT(proxy.IsJSProxy()); JSHandle proxyHandle(thread, proxy); // 5 ~ 6 Set internal slot of p to null. proxyHandle->SetTarget(thread, JSTaggedValue::Null()); proxyHandle->SetHandler(thread, JSTaggedValue::Null()); } JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError([[maybe_unused]] EcmaRuntimeCallInfo *argv) { THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "Under strict mode, 'caller' and 'arguments' properties must not be accessed.", JSTaggedValue::Exception()); } JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle &self) { return thread->GlobalConstants()->GetEmptyString(); } void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name) { ASSERT_PRINT(func->IsExtensible(), "Function must be extensible"); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle funcHandle(thread, func); { JSMutableHandle nameHandle(thread, JSTaggedValue::Undefined()); if (!name.IsSymbol()) { nameHandle.Update(name); } else { JSHandle nameBegin(thread, name); JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription(); if (description.IsUndefined()) { nameHandle.Update(thread->GlobalConstants()->GetEmptyString()); } else { JSHandle concatName; JSHandle leftBrackets = factory->NewFromCanBeCompressString("["); JSHandle rightBrackets = factory->NewFromCanBeCompressString("]"); concatName = factory->ConcatFromString( leftBrackets, JSHandle(thread, JSSymbol::Cast(nameBegin->GetHeapObject())->GetDescription())); concatName = factory->ConcatFromString(concatName, rightBrackets); nameHandle.Update(concatName.GetTaggedValue()); } } PropertyDescriptor nameDesc(thread, nameHandle, false, false, true); JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, thread->GlobalConstants()->GetHandledNameString(), nameDesc); } } JSHandle JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle constructor, JSHandle newTarget) { JSHandle ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor)); // newTarget is construct itself if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) { return ctorInitialJSHClass; } // newTarget is derived-class of constructor if (newTarget->IsJSFunction()) { JSHandle newTargetFunc = JSHandle::Cast(newTarget); if (newTargetFunc->IsDerivedConstructor()) { JSTaggedValue newTargetProto = JSHandle::Cast(newTarget)->GetPrototype(thread); if (newTargetProto == constructor.GetTaggedValue()) { return GetOrCreateDerivedJSHClass(thread, newTargetFunc, constructor, ctorInitialJSHClass); } } } // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype"). JSMutableHandle prototype(thread, JSTaggedValue::Undefined()); if (newTarget->IsJSFunction()) { JSHandle newTargetFunc = JSHandle::Cast(newTarget); FunctionKind kind = newTargetFunc->GetFunctionKind(); if (HasPrototype(kind)) { prototype.Update(PrototypeGetter(thread, JSHandle::Cast(newTargetFunc))); } } else { // Such case: bound function and define a "prototype" property. JSHandle customizePrototype = JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString()) .GetValue(); RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread); prototype.Update(customizePrototype.GetTaggedValue()); // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it. ctorInitialJSHClass = JSHandle(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor)); } if (!prototype->IsECMAObject()) { prototype.Update(constructor->GetFunctionPrototype()); } JSHandle newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass); newJSHClass->SetPrototype(thread, prototype); return newJSHClass; } JSHandle JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle derived, JSHandle constructor, JSHandle ctorInitialJSHClass) { JSTaggedValue protoOrDyn(derived->GetProtoOrDynClass()); // has cached JSHClass, return directly if (protoOrDyn.IsJSHClass()) { return JSHandle(thread, protoOrDyn); } JSHandle newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass); // guarante derived has function prototype JSHandle prototype(thread, derived->GetProtoOrDynClass()); ASSERT(!prototype->IsHole()); newJSHClass->SetPrototype(thread, prototype); derived->SetProtoOrDynClass(thread, newJSHClass); return newJSHClass; } // Those interface below is discarded void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle &env, const JSHandle &func, FunctionKind kind, bool strict) { InitializeJSFunction(thread, func, kind, strict); } bool JSFunction::IsDynClass(JSTaggedValue object) { return object.IsJSHClass(); } DynClass *JSFunction::GetOrCreateInitialDynClass(JSThread *thread, const JSHandle &fun) { return reinterpret_cast(JSFunction::GetOrCreateInitialJSHClass(thread, fun)); } JSHandle JSFunction::GetInstanceDynClass(JSThread *thread, JSHandle constructor, JSHandle newTarget) { return JSHandle(JSFunction::GetInstanceJSHClass(thread, constructor, newTarget)); } bool JSFunction::NameSetter(JSThread *thread, const JSHandle &self, const JSHandle &value, [[maybe_unused]] bool mayThrow) { if (self->IsPropertiesDict()) { // replace setter with value JSHandle nameString = thread->GlobalConstants()->GetHandledNameString(); return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue()); } self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue()); return true; } } // namespace panda::ecmascript