From d8872d26e481d05ceeb603fe1fb5c4ec89b7bbc0 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 18:43:05 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E5=A4=9A=E4=BD=99=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 7ee4c97..fd988ab 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -471,7 +471,7 @@ pesapi_value pesapi_get_arg(pesapi_callback_info pinfo, int index) } } -PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info pinfo) +pesapi_env pesapi_get_env(pesapi_callback_info pinfo) { return pesapiEnvFromQjsContext(pinfo->ctx); } From bccfdce336bc58141510717ccd0cea8cd03abf41 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 18:53:37 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E4=B8=80=E4=BA=9Bapi=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/PapiQuickjsImpl.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index fd988ab..46065e6 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -623,7 +623,13 @@ void pesapi_close_scope_placement(pesapi_scope scope) pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value pvalue, uint32_t internal_field_count) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + size_t totalSize = sizeof(pesapi_value_ref__) + sizeof(void*) * internal_field_count; + auto ret = (pesapi_value_ref)malloc(totalSize); + memset(ret, 0, totalSize); + JSValue* v = qjsValueFromPesapiValue(pvalue); + new (ret) pesapi_value_ref__(ctx, *v, internal_field_count); + return ret; } pesapi_value_ref pesapi_duplicate_value_ref(pesapi_value_ref value_ref) @@ -646,16 +652,31 @@ void pesapi_release_value_ref(pesapi_value_ref value_ref) pesapi_value pesapi_get_value_from_ref(pesapi_env env, pesapi_value_ref value_ref) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* v = allocValueInCurrentScope(ctx); + *v = JS_DupValue(ctx, value_ref->value_persistent); + return pesapiValueFromQjsValue(v); } void pesapi_set_ref_weak(pesapi_env env, pesapi_value_ref value_ref) { + auto ctx = qjsContextFromPesapiEnv(env); + JS_FreeValue(ctx, value_ref->value_persistent); } bool pesapi_set_owner(pesapi_env env, pesapi_value pvalue, pesapi_value powner) { - return false; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* obj = qjsValueFromPesapiValue(pvalue); + JSValue* owner = qjsValueFromPesapiValue(powner); + if (JS_IsObject(*owner)) + { + JSAtom key = JS_NewAtom(ctx, "_p_i_only_one_child"); + JS_DupValue(ctx, *obj); + JS_SetProperty(ctx, *owner, key, *obj); + JS_FreeAtom(ctx, key); + } + return true; } pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref) @@ -665,7 +686,8 @@ pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref) void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pinternal_field_count) { - return {}; + *pinternal_field_count = value_ref->internal_field_count; + return &value_ref->internal_fields[0]; } pesapi_value pesapi_get_property(pesapi_env env, pesapi_value pobject, const char* key) From fe5061cafd457a360e25e8e74ea4c3fd5218bdff Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Tue, 25 Feb 2025 19:18:03 +0800 Subject: [PATCH 03/10] add pesapi_call_function implement --- source/PapiQuickjsImpl.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 46065e6..e2865d0 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -748,7 +748,16 @@ void pesapi_set_property_uint32(pesapi_env env, pesapi_value pobject, uint32_t k pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_value this_object, int argc, const pesapi_value argv[]) { - return {}; + auto ctx = qjsContextFromPesapiEnv(env); + JSValue* func = qjsValueFromPesapiValue(pfunc); + JSValue* thisObj = qjsValueFromPesapiValue(this_object); + JSValue *js_argv = (JSValue*)alloca(argc * sizeof(JSValue)); + for (int i = 0; i < argc; ++i) { + js_argv[i] = *qjsValueFromPesapiValue(argv[i]); + } + JSValue* ret = allocValueInCurrentScope(ctx); + *ret = JS_Call(ctx, *func, *thisObj, argc, js_argv); + return pesapiValueFromQjsValue(ret); } pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path) From a62d6550ff16ff60830eb43a1a393a2d5ea18346 Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Tue, 25 Feb 2025 19:33:35 +0800 Subject: [PATCH 04/10] add pesapi_call_function testcase --- source/PapiQuickjsImpl.cpp | 2 +- test/papi_qjs_base_test.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index e2865d0..8135802 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -750,7 +750,7 @@ pesapi_value pesapi_call_function(pesapi_env env, pesapi_value pfunc, pesapi_val { auto ctx = qjsContextFromPesapiEnv(env); JSValue* func = qjsValueFromPesapiValue(pfunc); - JSValue* thisObj = qjsValueFromPesapiValue(this_object); + JSValue* thisObj = this_object ? qjsValueFromPesapiValue(this_object) : &literal_values_undefined; JSValue *js_argv = (JSValue*)alloca(argc * sizeof(JSValue)); for (int i = 0; i < argc; ++i) { js_argv[i] = *qjsValueFromPesapiValue(argv[i]); diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 91a5774..617830d 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -495,6 +495,27 @@ TEST_F(PApiBaseTest, RefArgument) { EXPECT_EQ(5, apis->get_value_int32(env, ret)); } +TEST_F(PApiBaseTest, CallFunction) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + function sub(x, y) { + return x - y; + } + sub; + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_function(env, ret)); + pesapi_value argv[2] {apis->create_int32(env, 5), apis->create_int32(env, 3)}; + auto func_call_ret = apis->call_function(env, ret, nullptr, 2, argv); + ASSERT_TRUE(apis->is_int32(env, func_call_ret)); + EXPECT_EQ(2, apis->get_value_int32(env, func_call_ret)); +} } // namespace qjsimpl } // namespace pesapi From 03d0239aea2d6112e6d598131b68310b49c1f644 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 21:00:05 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=B8=80=E4=BA=9Bwarni?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8d7c8b..f59af9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ if(MSVC) xcheck_add_c_compiler_flag(/wd4996) # -Wdeprecated-declarations xcheck_add_c_compiler_flag(/wd5045) # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified xcheck_add_c_compiler_flag(/wd4514) - xcheck_add_c_compiler_flag(/wd4514) + xcheck_add_c_compiler_flag(/wd4146) xcheck_add_c_compiler_flag(-fchar8_t) xcheck_add_c_compiler_flag(/Zc:char8_t) endif() @@ -193,15 +193,10 @@ target_compile_options(PapiQjs PRIVATE -fno-rtti > $<$: - /EHa- - /EHsc - /EHsc- - /GR- # 禁用RTTI + /EHa- # 禁用异常处理 + /GR- # 禁用RTTI > ) -#if(MSVC) -#target_compile_options(PapiQjs PRIVATE /EHsc) -#endif() target_compile_definitions(PapiRegister PUBLIC BUILDING_REGISTER_API_SHARED) target_compile_options(PapiRegister PRIVATE @@ -213,7 +208,6 @@ target_compile_options(PapiRegister PRIVATE > $<$: /EHa- - /EHsc- /GR- # 禁用RTTI > ) From be866e0a196851050dd3fa05e1963eddaa065964 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Feb 2025 21:04:48 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E5=BF=BD=E7=95=A5warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f59af9e..60db4f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ if(MSVC) xcheck_add_c_compiler_flag(/wd5045) # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified xcheck_add_c_compiler_flag(/wd4514) xcheck_add_c_compiler_flag(/wd4146) + xcheck_add_c_compiler_flag(/wd4334) xcheck_add_c_compiler_flag(-fchar8_t) xcheck_add_c_compiler_flag(/Zc:char8_t) endif() From 36d57f26db6e87abe861cc55df3591eac2589fa5 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 26 Feb 2025 10:08:03 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9F=BA=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 67 ++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 617830d..b9ddb64 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -7,12 +7,24 @@ namespace pesapi { namespace qjsimpl { -struct TestStruct { +struct TestStructBase { + TestStructBase(int b) { + this->b = b; + } + + int b; + int Foo(int a) + { + return a + b; + } +}; + +struct TestStruct : public TestStructBase { static int ctor_count; static int dtor_count; static TestStruct* lastCtorObject; static TestStruct* lastDtorObject; - TestStruct(int a) { + TestStruct(int a) : TestStructBase(a - 1) { this->a = a; ctor_count++; lastCtorObject = this; @@ -37,6 +49,8 @@ struct TestStruct { } }; +const void* baseTypeId = "TestStructBase"; + const void* typeId = "TestStruct"; int TestStruct::ctor_count = 0; @@ -57,6 +71,33 @@ static void TestStructFinalize(struct pesapi_ffi* apis, void* ptr, void* class_d delete (TestStruct*)ptr; } +static void BGetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStructBase*)apis->get_native_object_ptr(env, self); + apis->add_return(info, apis->create_int32(env, obj->b)); +} + +static void BSetterWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStructBase*)apis->get_native_object_ptr(env, self); + auto p0 = apis->get_arg(info, 0); + obj->b = apis->get_value_int32(env, p0); +} + +static void BaseFooWrap(struct pesapi_ffi* apis, pesapi_callback_info info) +{ + auto env = apis->get_env(info); + auto self = apis->get_this(info); + auto obj = (TestStructBase*)apis->get_native_object_ptr(env, self); + auto p0 = apis->get_arg(info, 0); + int a = apis->get_value_int32(env, p0); + apis->add_return(info, apis->create_int32(env, obj->Foo(a))); +} + static void AddWrap(struct pesapi_ffi* apis, pesapi_callback_info info) { auto env = apis->get_env(info); @@ -131,7 +172,25 @@ static void IncWrap(struct pesapi_ffi* apis, pesapi_callback_info info) class PApiBaseTest : public ::testing::Test { public: - static void SetUpTestCase() { + static void SetUpTestCase() { + // 封装TestStructBase + const int base_properties_count = 2; + pesapi_property_descriptor base_properties = pesapi_alloc_property_descriptors(base_properties_count); + pesapi_set_property_info(base_properties, 0, "b", false, BGetterWrap, BSetterWrap, NULL, NULL, NULL); + pesapi_set_method_info(base_properties, 1, "Foo", false, BaseFooWrap, NULL, NULL); + pesapi_define_class(baseTypeId, NULL, "TestStructBase", + [](struct pesapi_ffi* apis, pesapi_callback_info info) -> void* { // Ctor + auto env = apis->get_env(info); + auto p0 = apis->get_arg(info, 0); + int b = apis->get_value_int32(env, p0); + return new TestStructBase(b); + }, + [](struct pesapi_ffi* apis, void* ptr, void* class_data, void* env_private) { // Finalize + delete static_cast(ptr); + }, + base_properties_count, base_properties, NULL); + + // 封装TestStruct const int properties_count = 6; pesapi_property_descriptor properties = pesapi_alloc_property_descriptors(properties_count); pesapi_set_method_info(properties, 0, "Add", true, AddWrap, NULL, NULL); @@ -140,7 +199,7 @@ class PApiBaseTest : public ::testing::Test { pesapi_set_property_info(properties, 3, "ctor_count", true, CtorCountGetterWrap, CtorCountSetterWrap, NULL, NULL, NULL); pesapi_set_method_info(properties, 4, "GetSelf", false, GetSelfWrap, NULL, NULL); pesapi_set_method_info(properties, 5, "Inc", false, IncWrap, NULL, NULL); - pesapi_define_class(typeId, NULL, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); + pesapi_define_class(typeId, baseTypeId, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); } static void TearDownTestCase() { From 0486feb15ff21bbd552cbed4c0f9d2eb68228333 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 26 Feb 2025 10:10:37 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E5=A4=9A=E5=AF=B9=E8=B1=A1=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/papi_qjs_base_test.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index b9ddb64..28a9597 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -532,6 +532,26 @@ TEST_F(PApiBaseTest, ReturnAObject) { ASSERT_TRUE(apis->get_value_bool(env, ret)); } +TEST_F(PApiBaseTest, MutiObject) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + for (let i = 0; i < 1000; ++i) { + const obj = new TestStruct(123); + const self = obj.GetSelf(); + } + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); +} + TEST_F(PApiBaseTest, RefArgument) { auto env = apis->get_env_from_ref(env_ref); From 9962af928d4df207b77155a191e9aa7c3bf6d707 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 26 Feb 2025 13:02:05 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0JS=5FValueRefCount?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E9=97=AE=E9=A2=98=E5=AE=9A=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quickjs/quickjs.c | 9 +++++++++ quickjs/quickjs.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c index 7923022..2ca10d9 100644 --- a/quickjs/quickjs.c +++ b/quickjs/quickjs.c @@ -55893,4 +55893,13 @@ JS_BOOL JS_GetArrayBufferViewInfo(JSContext *ctx, JSValueConst obj, return TRUE; } +int JS_ValueRefCount(JSContext *ctx, JSValue v) +{ + if (JS_VALUE_HAS_REF_COUNT(v)) { + JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); + return p->ref_count; + } + return -1; +} + /*-------end additional function---------*/ diff --git a/quickjs/quickjs.h b/quickjs/quickjs.h index dfefc06..0041304 100644 --- a/quickjs/quickjs.h +++ b/quickjs/quickjs.h @@ -1049,6 +1049,8 @@ JS_BOOL JS_GetArrayBufferViewInfo(JSContext *ctx, JSValueConst obj, size_t *pbyte_length, size_t *pbytes_per_element); +int JS_ValueRefCount(JSContext *ctx, JSValue v); + /*-------end additional function---------*/ #ifdef __cplusplus From 640e4a9743bdf7a5df5477984c5b0cedc8b924f9 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 26 Feb 2025 13:31:32 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E7=BB=A7=E6=89=BF=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=92=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 17 ++++++++++++++--- source/PapiQuickjsImpl.cpp | 1 + test/papi_qjs_base_test.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index ec910c3..e5a9918 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -251,7 +251,7 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin { return JS_Throw(ctx, CppObjectMapper::CreateError(ctx, "no initialize function")); } - }, 0, 0, 3, &ctor_data[0]); + }, 0, 0, 3, &ctor_data[0]); // ref_count: 1 JS_SetConstructorBit(ctx, func, 1); @@ -295,11 +295,22 @@ JSValue CppObjectMapper::CreateClass(const puerts::JSClassDefinition* ClassDefin ++FunctionInfo; } - JS_SetConstructor(ctx, func, proto); + JS_SetConstructor(ctx, func, proto); // func ref_count: 2 JS_FreeValue(ctx, proto); + if (ClassDefinition->SuperTypeId) + { + if (auto SuperDefinition = puerts::FindClassByID(ClassDefinition->SuperTypeId)) + { + JSValue super_func = CreateClass(SuperDefinition); + JSValue parent_proto = JS_GetProperty(ctx, super_func, JS_ATOM_prototype); + JS_SetPrototype(ctx, proto, parent_proto); + JS_FreeValue(ctx, parent_proto); + } + } + TypeIdToFunctionMap[ClassDefinition->TypeId] = func; - JS_DupValue(ctx, func); //JS_FreeValue in Cleanup + //printf("register class %s, tid:%p, rc:%d, obj:%p\n", ClassDefinition->ScriptName, ClassDefinition->TypeId, JS_ValueRefCount(ctx, func), JS_VALUE_GET_PTR(func)); return func; } return it->second; diff --git a/source/PapiQuickjsImpl.cpp b/source/PapiQuickjsImpl.cpp index 8135802..6dacaea 100644 --- a/source/PapiQuickjsImpl.cpp +++ b/source/PapiQuickjsImpl.cpp @@ -197,6 +197,7 @@ pesapi_value pesapi_create_class(pesapi_env env, const void* type_id) auto ctx = qjsContextFromPesapiEnv(env); auto ret = allocValueInCurrentScope(ctx); *ret = pesapi::qjsimpl::CppObjectMapper::Get(ctx)->CreateClassByID(type_id); + JS_DupValue(ctx, *ret); return pesapiValueFromQjsValue(ret); } diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 28a9597..2a751e4 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -596,6 +596,32 @@ TEST_F(PApiBaseTest, CallFunction) { EXPECT_EQ(2, apis->get_value_int32(env, func_call_ret)); } +TEST_F(PApiBaseTest, SuperAccess) { + auto env = apis->get_env_from_ref(env_ref); + + auto code = R"( + (function() { + const TestStruct = loadClass('TestStruct'); + const obj = new TestStruct(123); + let ret = "" + obj.b + ":"; // 122 + obj.b = 5 + ret += obj.Foo(6); // 11 + return ret; + })(); + )"; + auto ret = apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + if (apis->has_caught(scope)) + { + printf("%s\n", apis->get_exception_as_string(scope, true)); + } + ASSERT_FALSE(apis->has_caught(scope)); + ASSERT_TRUE(apis->is_string(env, ret)); + char buff[1024]; + size_t len = sizeof(buff); + const char* str = apis->get_value_string_utf8(env, ret, buff, &len); + EXPECT_STREQ("122:11", str); +} + } // namespace qjsimpl } // namespace pesapi