Skip to content

Commit c09c658

Browse files
committed
improve jsc function call perf
1 parent fad3a11 commit c09c658

File tree

3 files changed

+73
-21
lines changed

3 files changed

+73
-21
lines changed

test-app/runtime/src/main/cpp/napi/jsc/jsc-api.cpp

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class NativeInfo {
217217
static T* GetNativeInfo(JSContextRef ctx, JSObjectRef obj, const char * propertyKey) {
218218
JSValueRef exception {};
219219
JSValueRef native_info = JSObjectGetProperty(ctx, obj, JSString(propertyKey), &exception);
220+
220221
NativeInfo* info = Get<NativeInfo>(JSValueToObject(ctx, native_info, &exception));
221222
if (info != nullptr && info->Type() == T::StaticType) {
222223
return reinterpret_cast<T*>(info);
@@ -349,6 +350,11 @@ class ConstructorInfo : public NativeInfo {
349350
JSClassRef _class;
350351
};
351352

353+
namespace xyz {
354+
static std::once_flag functionInfoOnceFlag;
355+
JSClassRef functionInfoClass {};
356+
}
357+
352358
class FunctionInfo : public NativeInfo {
353359
public:
354360
static const NativeType StaticType = NativeType::Function;
@@ -363,35 +369,44 @@ class FunctionInfo : public NativeInfo {
363369
if (info == nullptr) {
364370
return napi_set_last_error(env, napi_generic_failure);
365371
}
366-
367-
JSObjectRef function{JSObjectMakeFunctionWithCallback(env->context, JSString(utf8name), CallAsFunction)};
368-
// JSObjectRef prototype{JSObjectMake(env->context, info->_class, info)};
369-
//
370-
//
371-
// JSObjectSetPrototype(env->context, prototype, JSObjectGetPrototype(env->context, function));
372-
// JSObjectSetPrototype(env->context, function, prototype);
373-
374-
NativeInfo::SetNativeInfo(env->context, function, info->_class, "[[jsc_function_info]]", info);
375-
372+
JSObjectRef function = JSObjectMake(env->context, xyz::functionInfoClass, info);
376373
*result = ToNapi(function);
377374
return napi_ok;
378375
}
379376

377+
380378
private:
381379
FunctionInfo(napi_env env, napi_callback cb, void* data)
382380
: NativeInfo{NativeType::Function}
383381
, _env{env}
384382
, _cb{cb}
385383
, _data{data} {
386-
JSClassDefinition definition{kJSClassDefinitionEmpty};
387-
definition.className = "Native";
388-
definition.finalize = Finalize;
389-
_class = JSClassCreate(&definition);
384+
std::call_once(xyz::functionInfoOnceFlag, []() {
385+
JSClassDefinition definition{kJSClassDefinitionEmpty};
386+
definition.className = "NapiFunctionCallback";
387+
definition.callAsFunction = FunctionInfo::CallAsFunction;
388+
definition.attributes = kJSClassAttributeNoAutomaticPrototype;
389+
definition.initialize = FunctionInfo::initialize;
390+
definition.finalize = Finalize;
391+
xyz::functionInfoClass = JSClassCreate(&definition);
392+
});
393+
390394
}
391395

392-
~FunctionInfo() {
393-
JSClassRelease(_class);
396+
~FunctionInfo() {}
397+
398+
static void initialize(JSContextRef ctx, JSObjectRef object) {
399+
JSObjectRef global = JSContextGetGlobalObject(ctx);
400+
JSValueRef value =
401+
JSObjectGetProperty(ctx, global, JSString("Function"), nullptr);
402+
JSObjectRef funcCtor = JSValueToObject(ctx, value, nullptr);
403+
if (!funcCtor) {
404+
// We can't do anything if Function is not an object
405+
return;
394406
}
407+
JSValueRef funcProto = JSObjectGetPrototype(ctx, funcCtor);
408+
JSObjectSetPrototype(ctx, object, funcProto);
409+
}
395410

396411
// JSObjectCallAsFunctionCallback
397412
static JSValueRef CallAsFunction(JSContextRef ctx,
@@ -401,7 +416,7 @@ class FunctionInfo : public NativeInfo {
401416
const JSValueRef arguments[],
402417
JSValueRef* exception) {
403418
// FunctionInfo* info = NativeInfo::Get<FunctionInfo>(function);
404-
FunctionInfo* info = NativeInfo::GetNativeInfo<FunctionInfo>(ctx, function, "[[jsc_function_info]]");
419+
FunctionInfo* info = reinterpret_cast<FunctionInfo *>(JSObjectGetPrivate(function));
405420

406421
// Make sure any errors encountered last time we were in N-API are gone.
407422
napi_clear_last_error(info->_env);
@@ -411,6 +426,7 @@ class FunctionInfo : public NativeInfo {
411426
cbinfo.newTarget = nullptr;
412427
cbinfo.argc = argumentCount;
413428
cbinfo.argv = ToNapi(arguments);
429+
414430
cbinfo.data = info->_data;
415431

416432
napi_value result = info->_cb(info->_env, &cbinfo);
@@ -433,9 +449,9 @@ class FunctionInfo : public NativeInfo {
433449
napi_env _env;
434450
napi_callback _cb;
435451
void* _data;
436-
JSClassRef _class;
437452
};
438453

454+
439455
template<typename T, NativeType TType>
440456
class BaseInfoT : public NativeInfo {
441457
public:
@@ -715,6 +731,15 @@ void NapiEnvironment::deinit_refs() {
715731
}
716732
}
717733

734+
void NapiEnvironment::init_symbol(JSValueRef &symbol, const char *description) {
735+
symbol = JSValueMakeSymbol(context, JSString(description));
736+
JSValueProtect(context, symbol);
737+
}
738+
739+
void NapiEnvironment::deinit_symbol(JSValueRef symbol) {
740+
JSValueUnprotect(context, symbol);
741+
}
742+
718743
// Warning: Keep in-sync with napi_status enum
719744
static const char* error_messages[] = {
720745
nullptr,

test-app/runtime/src/main/cpp/napi/jsc/jsc-api.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,46 @@ struct NapiEnvironment {
2020
std::unordered_set<napi_value> active_ref_values{};
2121
std::list<napi_ref> strong_refs{};
2222

23+
JSValueRef constructor_info_symbol{};
24+
JSValueRef function_info_symbol{};
25+
JSValueRef reference_info_symbol{};
26+
JSValueRef wrapper_info_symbol{};
27+
2328
const std::thread::id thread_id{std::this_thread::get_id()};
2429

2530
NapiEnvironment(JSGlobalContextRef context) : context{context} {
31+
napi_envs[context] = this;
2632
JSGlobalContextRetain(context);
33+
init_symbol(constructor_info_symbol, "NS_ConstructorInfo");
34+
init_symbol(function_info_symbol, "NS_FunctionInfo");
35+
init_symbol(reference_info_symbol, "NS_ReferenceInfo");
36+
init_symbol(wrapper_info_symbol, "NS_WrapperInfo");
2737
}
2838

2939
~NapiEnvironment() {
3040
deinit_refs();
3141
JSGlobalContextRelease(context);
42+
deinit_symbol(wrapper_info_symbol);
43+
deinit_symbol(reference_info_symbol);
44+
deinit_symbol(function_info_symbol);
45+
deinit_symbol(constructor_info_symbol);
46+
napi_envs.erase(context);
47+
}
48+
49+
static napi_env get(JSGlobalContextRef context) {
50+
auto it = napi_envs.find(context);
51+
if (it != napi_envs.end()) {
52+
return it->second;
53+
} else {
54+
return nullptr;
55+
}
3256
}
3357

3458
private:
59+
static inline std::unordered_map<JSGlobalContextRef, napi_env> napi_envs{};
3560
void deinit_refs();
61+
void init_symbol(JSValueRef& symbol, const char* description);
62+
void deinit_symbol(JSValueRef symbol);
3663
};
3764

3865
#define RETURN_STATUS_IF_FALSE(env, condition, status) \

test-app/runtime/src/main/cpp/napi/jsc/jsr.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ typedef struct NapiRuntime *napi_runtime;
1212

1313
class NapiScope {
1414
public:
15-
explicit NapiScope(napi_env env)
15+
explicit NapiScope(napi_env env, bool openHandle = true)
1616
: env_(env)
1717
{
18-
napi_open_handle_scope(env_, &napiHandleScope_);
18+
// napi_open_handle_scope(env_, &napiHandleScope_);
1919
}
2020

2121
~NapiScope() {
22-
napi_close_handle_scope(env_, napiHandleScope_);
22+
// napi_close_handle_scope(env_, napiHandleScope_);
2323
}
2424

2525
private:

0 commit comments

Comments
 (0)