diff --git a/BUILD.gn b/BUILD.gn index 2929c7dc50115eb07570a5cc7c2415f4e24cdcbe..5004a81c046489524f31baa003cdbdcd78e4e1d3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1181,6 +1181,7 @@ ecma_source += [ "ecmascript/cross_vm/unified_gc/unified_gc.cpp", "ecmascript/cross_vm/unified_gc/unified_gc_marker.cpp", "ecmascript/cross_vm/builtins_gc_hybrid.cpp", + "ecmascript/cross_vm/dynamic_object_accessor_util.cpp", "ecmascript/cross_vm/heap_hybrid.cpp", "ecmascript/cross_vm/jsnapi_expo_hybrid.cpp", "ecmascript/cross_vm/object_factory_hybrid.cpp", diff --git a/ecmascript/cross_vm/dynamic_object_accessor_util.cpp b/ecmascript/cross_vm/dynamic_object_accessor_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d8e2cf8a38627d800e5b367ce4eb5df7bd6bc5b --- /dev/null +++ b/ecmascript/cross_vm/dynamic_object_accessor_util.cpp @@ -0,0 +1,112 @@ +/* + * 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 "common_interfaces/objects/dynamic_object_accessor_util.h" +#include "ecmascript/checkpoint/thread_state_transition.h" +#include "ecmascript/debugger/js_debugger_manager.h" +#include "ecmascript/dfx/stackinfo/js_stackinfo.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env_constants-inl.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/interpreter/interpreter_assembly.h" +#include "ecmascript/js_function.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/js_thread.h" +#include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/napi/include/jsnapi_expo.h" +#include "ecmascript/napi/jsnapi_helper.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/object_operator.h" + + +namespace common { + +using panda::ecmascript::EcmaHandleScope; +using panda::ecmascript::EcmaVM; +using panda::ecmascript::EcmaRuntimeCallInfo; +using panda::ecmascript::JSFunction; +using panda::ecmascript::JSHandle; +using panda::ecmascript::JSTaggedValue; +using panda::ecmascript::JSThread; +using panda::ecmascript::ObjectFactory; +using panda::ecmascript::TaggedObject; +using panda::FunctionCallScope; +using panda::EscapeLocalScope; +using panda::JSValueRef; +using panda::JSNApi; + + +TaggedType* DynamicObjectAccessorUtil::GetProperty(const BaseObject *obj, const char *name) +{ + JSThread *jsThread = JSThread::GetCurrent(); + panda::ecmascript::ThreadManagedScope managedScope(jsThread); + ObjectFactory *factory = jsThread->GetEcmaVM()->GetFactory(); + panda::EscapeLocalScope scope(jsThread->GetEcmaVM()); + JSHandle holderHandle(jsThread, TaggedObject::Cast(obj)); + JSHandle keyHandle(factory->NewFromUtf8(name)); + auto resultValue = JSTaggedValue::GetProperty(jsThread, holderHandle, keyHandle).GetValue(); + auto ret = scope.Escape(panda::JSNApiHelper::ToLocal(resultValue)); + return reinterpret_cast(*ret); +} + +bool DynamicObjectAccessorUtil::SetProperty(const BaseObject *obj, const char *name, TaggedType value) +{ + JSThread *jsThread = JSThread::GetCurrent(); + panda::ecmascript::ThreadManagedScope managedScope(jsThread); + ObjectFactory *factory = jsThread->GetEcmaVM()->GetFactory(); + panda::EscapeLocalScope scope(jsThread->GetEcmaVM()); + JSHandle holderHandle(jsThread, TaggedObject::Cast(obj)); + JSHandle keyHandle(factory->NewFromUtf8(name)); + JSTaggedValue taggedValue(value); + JSHandle valueHandle(jsThread, taggedValue); + return JSTaggedValue::SetProperty(jsThread, holderHandle, keyHandle, valueHandle); +} + +TaggedType* DynamicObjectAccessorUtil::CallFunction(TaggedType jsThis, TaggedType function, int32_t argc, + TaggedType *argv) +{ + auto vm = JSThread::GetCurrent()->GetEcmaVM(); + EscapeLocalScope scope(vm); + TaggedType *undefindType = reinterpret_cast(*(JSValueRef::Undefined(vm))); + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, undefindType); + panda::ecmascript::ThreadManagedScope managedScope(thread); + FunctionCallScope callScope(EcmaVM::ConstCast(vm)); + JSTaggedValue funcValue(function); + if (!funcValue.IsCallable()) { + return undefindType; + } + vm->GetJsDebuggerManager()->ClearSingleStepper(); + JSHandle func(thread, funcValue); + LOG_IF_SPECIAL(func, ERROR); + JSTaggedValue thisObj(jsThis); + JSHandle thisValue(thread, thisObj); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + panda::ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisValue, undefined, argc); + RETURN_VALUE_IF_ABRUPT(thread, undefindType); + info->SetCallArg(argc, argv); + JSTaggedValue result = JSFunction::Call(info); + if (thread->HasPendingException()) { + panda::ecmascript::JsStackInfo::BuildCrashInfo(thread); + } + RETURN_VALUE_IF_ABRUPT(thread, undefindType); + EcmaVM::ClearKeptObjects(thread); + vm->GetJsDebuggerManager()->NotifyReturnNative(); + JSHandle resultValue(thread, result); + auto ret = scope.Escape(panda::JSNApiHelper::ToLocal(resultValue)); + return reinterpret_cast(*ret); +} +} \ No newline at end of file diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn index 959cc99191d8d24b7605ecba8d618ef828c1a1b7..abe0135a8e51f767827c537e8df1ca083060c625 100644 --- a/ecmascript/tests/BUILD.gn +++ b/ecmascript/tests/BUILD.gn @@ -1518,6 +1518,32 @@ host_unittest_action("Dynamic_Object_Accessor_Test") { deps += hiviewdfx_deps } +host_unittest_action("Dynamic_Object_Accessor_Util_Test") { + module_out_path = module_output_path + + sources = [ + # test file + "dynamic_object_accessor_util_test.cpp", + ] + + configs = [ + "../../:ecma_test_config", + "../../:icu_path_test_config", + ] + + deps = [ "../../:libark_jsruntime_test" ] + + # hiviewdfx libraries + external_deps = hiviewdfx_ext_deps + external_deps += [ + "icu:shared_icui18n", + "icu:shared_icuuc", + "runtime_core:libarkassembler_static", + "runtime_core:libarkverifier", + ] + deps += hiviewdfx_deps +} + host_unittest_action("JS_Object_Test") { module_out_path = module_output_path @@ -3775,6 +3801,7 @@ group("host_unittest") { ":Sendable_JsSendableArrayBuffer_TestAction", ":Sendable_JsSharedArray_TestAction", ":Sendable_SharedObjectFactory_TestAction", + ":Dynamic_Object_Accessor_Util_TestAction", ] if (is_mac) { diff --git a/ecmascript/tests/dynamic_object_accessor_util_test.cpp b/ecmascript/tests/dynamic_object_accessor_util_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cdc4b250a3cfbb360a308898eb721b8158203ea1 --- /dev/null +++ b/ecmascript/tests/dynamic_object_accessor_util_test.cpp @@ -0,0 +1,52 @@ +/* + * 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 "common_interfaces/objects/dynamic_object_accessor_util.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::base; + +namespace panda::test { +class DynamicObjectAccessorUtilTest : public BaseTestWithScope {}; + +static JSHandle JSObjectCreate(JSThread *thread) +{ + JSHandle globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); + auto jsFunc = globalEnv->GetObjectFunction().GetObject(); + JSHandle objFunc(thread, jsFunc); + auto *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle jsObject = factory->NewJSObjectByConstructor(JSHandle(objFunc), objFunc); + return jsObject; +} + +HWTEST_F_L0(DynamicObjectAccessorUtilTest, SetGetProperty01) +{ + JSHandle jsobject = JSObjectCreate(thread); + EXPECT_TRUE(*jsobject != nullptr); + + char key[] = "name"; + int value = 123; + JSTaggedValue taggedValue(value); + + auto setResult = common::DynamicObjectAccessorUtil::SetProperty(jsobject.GetTaggedValue().GetTaggedObject(), key, + taggedValue.GetRawData()); + EXPECT_EQ(setResult, true); + auto taggedType = common::DynamicObjectAccessorUtil::GetProperty(jsobject.GetTaggedValue().GetTaggedObject(), key); + EXPECT_EQ(JSTaggedValue(*taggedType).GetInt(), value); +} +} // namespace panda::test \ No newline at end of file diff --git a/libark_jsruntime.map b/libark_jsruntime.map index 2abb6f8faf64ebae908ee986a5e893eee1dbdd35..b01cda142864a327e92eddee2b47514580a3b1b5 100644 --- a/libark_jsruntime.map +++ b/libark_jsruntime.map @@ -128,6 +128,7 @@ common::Log::*; common::AndroidLog*; common::ThreadHolder::*; + common::DynamicObjectAccessorUtil::*; panda::ecmascript::AotCrashInfo*; panda::ecmascript::Method::*;