/* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/module/static/static_module_proxy_handler.h" #include "ecmascript/global_env.h" #include "ecmascript/object_factory-inl.h" #include "ecmascript/module/module_path_helper.h" #include "ecmascript/module/js_module_deregister.h" #include "ecmascript/module/js_shared_module_manager.h" #include "ecmascript/shared_objects/js_shared_array.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/module/module_data_extractor.h" #include "ecmascript/builtins/builtins_promise_job.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_promise.h" #include "ecmascript/module/module_path_helper.h" namespace panda::ecmascript { JSHandle StaticModuleProxyHandler::CreateStaticModuleProxyHandler(JSThread *thread, const JSHandle exportObject) { EcmaVM *vm = thread->GetEcmaVM(); ObjectFactory *factory = vm->GetFactory(); JSHandle targetHandler(factory->NewJSFunction(vm->GetGlobalEnv())); JSHandle setPrototype(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::SetPrototype))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledSetPrototypeOfString(), setPrototype); JSHandle preventExtensions(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::PreventExtensions))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledPreventExtensionsString(), preventExtensions); JSHandle getOwnProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::GetOwnProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledGetOwnPropertyDescriptorString(), getOwnProperty); JSHandle defineOwnProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::DefineOwnProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledDefinePropertyString(), defineOwnProperty); JSHandle hasProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::HasProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledHasString(), hasProperty); JSHandle getProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::GetProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledGetString(), getProperty); JSHandle setProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::SetProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledSetString(), setProperty); JSHandle deleteProperty(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::DeleteProperty))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledDeletePropertyString(), deleteProperty); JSHandle ownPropertyKeys(factory->NewJSFunction(vm->GetGlobalEnv(), reinterpret_cast(StaticModuleProxyHandler::OwnPropertyKeys))); JSTaggedValue::SetProperty(thread, targetHandler, thread->GlobalConstants()->GetHandledOwnKeysString(), ownPropertyKeys); return JSProxy::ProxyCreate(thread, exportObject, targetHandler); } JSTaggedValue StaticModuleProxyHandler::GetProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle obj(argv->GetCallArg(FIRST)); JSHandle key(argv->GetCallArg(SECOND)); // 1. Assert: IsPropertyKey(P) is true. // 2. If Type(P) is Symbol, then // a. Return ? OrdinaryGet(O, P, Receiver). return GetPropertyInternal(thread, obj, key); } JSTaggedValue StaticModuleProxyHandler::GetPropertyInternal(JSThread *thread, const JSHandle &obj, const JSHandle &key) { // 1. Assert: IsPropertyKey(P) is true. ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); // 2. If Type(P) is Symbol, then // a. Return ? OrdinaryGet(O, P, Receiver). return JSObject::GetProperty(thread, obj, key).GetValue().GetTaggedValue(); } JSTaggedValue StaticModuleProxyHandler::OwnPropertyKeys(EcmaRuntimeCallInfo *argv) { JSHandle obj(argv->GetCallArg(FIRST)); JSThread *thread = argv->GetThread(); JSHandle symbolKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle(obj)); //todo copy array JSHandle propertyKeys = JSArray::CreateArrayFromList(thread, symbolKeys); return propertyKeys.GetTaggedValue(); } bool StaticModuleProxyHandler::GetOwnPropertyInternal(JSThread *thread, const JSHandle &obj, const JSHandle &key, PropertyDescriptor &desc) { ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); // 1. If Type(P) is Symbol, return OrdinaryGetOwnProperty(O, P). if (key->IsSymbol()) { return JSObject::GetOwnProperty(thread, JSHandle(obj), key, desc); } // 2. Let value be ? O.[[Get]](P, O). JSHandle value(thread, StaticModuleProxyHandler::GetPropertyInternal(thread, obj, key)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); if (value->IsUndefined()) { return false; } // 3. Return PropertyDescriptor { // [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }. desc.SetValue(value); desc.SetEnumerable(true); desc.SetWritable(true); desc.SetConfigurable(false); return true; } JSTaggedValue StaticModuleProxyHandler::OwnEnumPropertyKeys(EcmaRuntimeCallInfo *argv) { JSHandle obj(argv->GetCallArg(FIRST)); JSThread *thread = argv->GetThread(); JSHandle symbolKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle(obj)); //todo copy array JSHandle propertyKeys = JSArray::CreateArrayFromList(thread, symbolKeys); return propertyKeys.GetTaggedValue(); } JSTaggedValue StaticModuleProxyHandler::PreventExtensions(EcmaRuntimeCallInfo *argv) { return JSTaggedValue::True(); } JSTaggedValue StaticModuleProxyHandler::DefineOwnProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle obj(argv->GetCallArg(FIRST)); JSHandle key(argv->GetCallArg(SECOND)); JSHandle descObj(argv->GetCallArg(THIRD)); PropertyDescriptor desc(thread); if (!descObj->IsUndefined()) { JSObject::ToPropertyDescriptor(thread, descObj, desc); } // 1. If Type(P) is Symbol, return ! OrdinaryDefineOwnProperty(O, P, Desc). if (key->IsSymbol()) { bool res = JSObject::OrdinaryDefineOwnProperty(thread, JSHandle(obj), key, desc); return JSTaggedValue(res); } // 2. Let current be ? O.[[GetOwnProperty]](P). PropertyDescriptor current(thread); // 3. If current is undefined, return false. if (!GetOwnPropertyInternal(thread, obj, key, current)) { return JSTaggedValue::False(); } // 4. If Desc has a [[Configurable]] field and Desc.[[Configurable]] is true, return false. // 5. If Desc has an [[Enumerable]] field and Desc.[[Enumerable]] is false, return false. // 6. If IsAccessorDescriptor(Desc) is true, return false. // 7. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, return false. if (desc.IsAccessorDescriptor()) { return JSTaggedValue::False(); } if (desc.HasConfigurable() && desc.IsConfigurable()) { return JSTaggedValue::False(); } if (desc.HasEnumerable() && !desc.IsEnumerable()) { return JSTaggedValue::False(); } if (desc.HasWritable() && !desc.IsWritable()) { return JSTaggedValue::False(); } // 8. If Desc has a [[Value]] field, return SameValue(Desc.[[Value]], current.[[Value]]). if (desc.HasValue()) { JSHandle descValue = desc.GetValue(); JSHandle currentValue = current.GetValue(); return JSTaggedValue(JSTaggedValue::SameValue(thread, descValue, currentValue)); } // 9. Return true. return JSTaggedValue::True(); } JSTaggedValue StaticModuleProxyHandler::HasProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle obj(argv->GetCallArg(FIRST)); JSHandle key(argv->GetCallArg(SECOND)); return JSTaggedValue(JSObject::HasProperty(thread, JSHandle(obj), key)); } JSTaggedValue StaticModuleProxyHandler::SetPrototype(EcmaRuntimeCallInfo *argv) { // 1. Assert: Either Type(V) is Object or Type(V) is Null. JSHandle proto(argv->GetCallArg(SECOND)); ASSERT(proto->IsECMAObject() || proto->IsNull()); return JSTaggedValue(proto->IsNull()); } JSTaggedValue StaticModuleProxyHandler::GetPrototype(EcmaRuntimeCallInfo *argv) { // 1. Assert: Either Type(V) is Object or Type(V) is Null. return JSTaggedValue::Null(); } JSTaggedValue StaticModuleProxyHandler::GetOwnProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle obj(argv->GetCallArg(FIRST)); JSHandle key(argv->GetCallArg(SECOND)); JSHandle descObj(argv->GetCallArg(THIRD)); PropertyDescriptor desc(thread); if (!descObj->IsUndefined()) { JSObject::ToPropertyDescriptor(thread, descObj, desc); } return JSTaggedValue(GetOwnPropertyInternal(thread, obj, key, desc)); } JSTaggedValue StaticModuleProxyHandler::SetProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle mayThrow(argv->GetCallArg(FIRST)); if (mayThrow->ToBoolean()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property of Object Module", JSTaggedValue::False()); } return JSTaggedValue::False(); } JSTaggedValue StaticModuleProxyHandler::DeleteProperty(EcmaRuntimeCallInfo *argv) { JSThread *thread = argv->GetThread(); JSHandle obj(argv->GetCallArg(FIRST)); JSHandle key(argv->GetCallArg(SECOND)); // 1. Assert: IsPropertyKey(P) is true. ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); // 2. If Type(P) is Symbol, then // Return ? OrdinaryDelete(O, P). if (key->IsSymbol()) { return JSTaggedValue(JSObject::DeleteProperty(thread, JSHandle(obj), key)); } // 3. Let exports be O.[[Exports]]. JSHandle value(thread, GetPropertyInternal(thread, obj, key)); // 4. If P is an element of exports, return false. if (value->IsUndefined()) { return JSTaggedValue::True(); } return JSTaggedValue::False(); } JSTaggedValue StaticModuleProxyHandler::IsExtensible(EcmaRuntimeCallInfo *argv) { return JSTaggedValue::False(); } } // namespace panda::ecmascript