Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

合入Dev #3

Merged
merged 10 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ 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(/wd4334)
xcheck_add_c_compiler_flag(-fchar8_t)
xcheck_add_c_compiler_flag(/Zc:char8_t)
endif()
Expand Down Expand Up @@ -193,15 +194,10 @@ target_compile_options(PapiQjs PRIVATE
-fno-rtti
>
$<$<CXX_COMPILER_ID:MSVC>:
/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
Expand All @@ -213,7 +209,6 @@ target_compile_options(PapiRegister PRIVATE
>
$<$<CXX_COMPILER_ID:MSVC>:
/EHa-
/EHsc-
/GR- # 禁用RTTI
>
)
Expand Down
9 changes: 9 additions & 0 deletions quickjs/quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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---------*/
2 changes: 2 additions & 0 deletions quickjs/quickjs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 14 additions & 3 deletions source/CppObjectMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
44 changes: 38 additions & 6 deletions source/PapiQuickjsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -471,7 +472,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);
}
Expand Down Expand Up @@ -623,7 +624,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)
Expand All @@ -646,16 +653,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)
Expand All @@ -665,7 +687,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)
Expand Down Expand Up @@ -726,7 +749,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 = 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]);
}
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)
Expand Down
134 changes: 130 additions & 4 deletions test/papi_qjs_base_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,6 +49,8 @@ struct TestStruct {
}
};

const void* baseTypeId = "TestStructBase";

const void* typeId = "TestStruct";

int TestStruct::ctor_count = 0;
Expand All @@ -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);
Expand Down Expand Up @@ -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<TestStructBase*>(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);
Expand All @@ -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() {
Expand Down Expand Up @@ -473,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);

Expand All @@ -495,6 +574,53 @@ 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));
}

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
Expand Down
Loading