Skip to content

Commit

Permalink
Merge pull request #3 from puerts/dev
Browse files Browse the repository at this point in the history
合入Dev
  • Loading branch information
chexiongsheng authored Feb 26, 2025
2 parents dbf7efd + 640e4a9 commit 7431cc6
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 22 deletions.
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

0 comments on commit 7431cc6

Please sign in to comment.