Skip to content

Commit 7ea29d6

Browse files
committed
perf(ios): add direct gsd backends for engines
1 parent ceb251c commit 7ea29d6

14 files changed

Lines changed: 1971 additions & 19 deletions

NativeScript/CMakeLists.txt

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}")
2020
# Arguments
2121
set(TARGET_PLATFORM "macos" CACHE STRING "Target platform for the Objective-C bridge")
2222
set(TARGET_ENGINE "v8" CACHE STRING "Target JS engine for the NativeScript runtime")
23-
set(NS_GSD_BACKEND "auto" CACHE STRING "Generated signature dispatch backend: auto, v8, napi, or none")
23+
set(NS_GSD_BACKEND "auto" CACHE STRING "Generated signature dispatch backend: auto, v8, jsc, quickjs, hermes, napi, or none")
2424
set(METADATA_SIZE 0 CACHE STRING "Size of embedded metadata in bytes")
2525
set(BUILD_CLI_BINARY OFF CACHE BOOL "Build the NativeScript CLI binary")
2626
set(BUILD_MACOS_NODE_API OFF CACHE BOOL "Build the NativeScript macOS Node API dylib")
27-
set_property(CACHE NS_GSD_BACKEND PROPERTY STRINGS auto v8 napi none)
27+
set_property(CACHE NS_GSD_BACKEND PROPERTY STRINGS auto v8 jsc quickjs hermes napi none)
2828

2929
if (BUILD_MACOS_NODE_API)
3030
set(BUILD_FRAMEWORK OFF)
@@ -137,10 +137,19 @@ message(STATUS "GENERIC_NAPI = ${GENERIC_NAPI}")
137137
if(NS_GSD_BACKEND STREQUAL "auto")
138138
if(TARGET_ENGINE_V8)
139139
set(NS_EFFECTIVE_GSD_BACKEND "v8")
140+
elseif(TARGET_ENGINE_JSC)
141+
set(NS_EFFECTIVE_GSD_BACKEND "jsc")
142+
elseif(TARGET_ENGINE_QUICKJS)
143+
set(NS_EFFECTIVE_GSD_BACKEND "quickjs")
144+
elseif(TARGET_ENGINE_HERMES)
145+
set(NS_EFFECTIVE_GSD_BACKEND "hermes")
140146
else()
141147
set(NS_EFFECTIVE_GSD_BACKEND "napi")
142148
endif()
143149
elseif(NS_GSD_BACKEND STREQUAL "v8" OR
150+
NS_GSD_BACKEND STREQUAL "jsc" OR
151+
NS_GSD_BACKEND STREQUAL "quickjs" OR
152+
NS_GSD_BACKEND STREQUAL "hermes" OR
144153
NS_GSD_BACKEND STREQUAL "napi" OR
145154
NS_GSD_BACKEND STREQUAL "none")
146155
set(NS_EFFECTIVE_GSD_BACKEND "${NS_GSD_BACKEND}")
@@ -151,6 +160,15 @@ endif()
151160
if(NS_EFFECTIVE_GSD_BACKEND STREQUAL "v8" AND NOT TARGET_ENGINE_V8)
152161
message(FATAL_ERROR "NS_GSD_BACKEND=v8 requires TARGET_ENGINE=v8")
153162
endif()
163+
if(NS_EFFECTIVE_GSD_BACKEND STREQUAL "jsc" AND NOT TARGET_ENGINE_JSC)
164+
message(FATAL_ERROR "NS_GSD_BACKEND=jsc requires TARGET_ENGINE=jsc")
165+
endif()
166+
if(NS_EFFECTIVE_GSD_BACKEND STREQUAL "quickjs" AND NOT TARGET_ENGINE_QUICKJS)
167+
message(FATAL_ERROR "NS_GSD_BACKEND=quickjs requires TARGET_ENGINE=quickjs")
168+
endif()
169+
if(NS_EFFECTIVE_GSD_BACKEND STREQUAL "hermes" AND NOT TARGET_ENGINE_HERMES)
170+
message(FATAL_ERROR "NS_GSD_BACKEND=hermes requires TARGET_ENGINE=hermes")
171+
endif()
154172

155173
message(STATUS "NS_GSD_BACKEND = ${NS_GSD_BACKEND} (${NS_EFFECTIVE_GSD_BACKEND})")
156174

@@ -254,6 +272,7 @@ if(ENABLE_JS_RUNTIME)
254272
set(SOURCE_FILES
255273
${SOURCE_FILES}
256274
napi/hermes/jsr.cpp
275+
ffi/HermesFastNativeApi.mm
257276
)
258277

259278
elseif(TARGET_ENGINE_QUICKJS)
@@ -389,11 +408,17 @@ elseif(TARGET_ENGINE_JSC)
389408
endif()
390409

391410
if(NS_EFFECTIVE_GSD_BACKEND STREQUAL "v8")
392-
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=1 NS_GSD_BACKEND_NAPI=0)
411+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=1 NS_GSD_BACKEND_JSC=0 NS_GSD_BACKEND_QUICKJS=0 NS_GSD_BACKEND_HERMES=0 NS_GSD_BACKEND_NAPI=0)
412+
elseif(NS_EFFECTIVE_GSD_BACKEND STREQUAL "jsc")
413+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_JSC=1 NS_GSD_BACKEND_QUICKJS=0 NS_GSD_BACKEND_HERMES=0 NS_GSD_BACKEND_NAPI=0)
414+
elseif(NS_EFFECTIVE_GSD_BACKEND STREQUAL "quickjs")
415+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_JSC=0 NS_GSD_BACKEND_QUICKJS=1 NS_GSD_BACKEND_HERMES=0 NS_GSD_BACKEND_NAPI=0)
416+
elseif(NS_EFFECTIVE_GSD_BACKEND STREQUAL "hermes")
417+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_JSC=0 NS_GSD_BACKEND_QUICKJS=0 NS_GSD_BACKEND_HERMES=1 NS_GSD_BACKEND_NAPI=0)
393418
elseif(NS_EFFECTIVE_GSD_BACKEND STREQUAL "napi")
394-
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_NAPI=1)
419+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_JSC=0 NS_GSD_BACKEND_QUICKJS=0 NS_GSD_BACKEND_HERMES=0 NS_GSD_BACKEND_NAPI=1)
395420
else()
396-
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_NAPI=0)
421+
target_compile_definitions(${NAME} PRIVATE NS_GSD_BACKEND_V8=0 NS_GSD_BACKEND_JSC=0 NS_GSD_BACKEND_QUICKJS=0 NS_GSD_BACKEND_HERMES=0 NS_GSD_BACKEND_NAPI=0)
397422
endif()
398423

399424
set(FRAMEWORK_VERSION_VALUE "${VERSION}")

NativeScript/ffi/CFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class CFunction {
2828
uint64_t dispatchId = 0;
2929
void* preparedInvoker = nullptr;
3030
void* napiInvoker = nullptr;
31+
void* engineDirectInvoker = nullptr;
3132
void* v8Invoker = nullptr;
3233
};
3334

NativeScript/ffi/CFunction.mm

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
183183
function->dispatchId = 0;
184184
function->preparedInvoker = nullptr;
185185
function->napiInvoker = nullptr;
186+
function->engineDirectInvoker = nullptr;
186187
function->v8Invoker = nullptr;
187188
}
188189
return;
@@ -199,6 +200,8 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
199200
function->preparedInvoker =
200201
reinterpret_cast<void*>(lookupCFunctionPreparedInvoker(function->dispatchId));
201202
function->napiInvoker = reinterpret_cast<void*>(lookupCFunctionNapiInvoker(function->dispatchId));
203+
function->engineDirectInvoker =
204+
reinterpret_cast<void*>(lookupCFunctionEngineDirectInvoker(function->dispatchId));
202205
#ifdef TARGET_ENGINE_V8
203206
function->v8Invoker = reinterpret_cast<void*>(lookupCFunctionV8Invoker(function->dispatchId));
204207
#endif
@@ -309,6 +312,8 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
309312
ensureCFunctionDispatchLookup(func, cif);
310313
auto preparedInvoker = reinterpret_cast<CFunctionPreparedInvoker>(func->preparedInvoker);
311314
auto napiInvoker = reinterpret_cast<CFunctionNapiInvoker>(func->napiInvoker);
315+
auto engineDirectInvoker =
316+
reinterpret_cast<CFunctionEngineDirectInvoker>(func->engineDirectInvoker);
312317

313318
MDFunctionFlag functionFlags =
314319
bridgeState->metadata->getFunctionFlag(offset + sizeof(MDSectionOffset) * 2);
@@ -337,9 +342,14 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
337342
const bool isMainEntrypoint =
338343
strcmp(name, "UIApplicationMain") == 0 || strcmp(name, "NSApplicationMain") == 0;
339344

340-
if (napiInvoker != nullptr && !cif->skipGeneratedNapiDispatch && !isMainEntrypoint) {
345+
if ((engineDirectInvoker != nullptr ||
346+
(napiInvoker != nullptr && !cif->skipGeneratedNapiDispatch)) &&
347+
!isMainEntrypoint) {
341348
@try {
342-
if (!napiInvoker(env, cif, func->fnptr, invocationArgs, cif->rvalue)) {
349+
bool invoked = engineDirectInvoker != nullptr
350+
? engineDirectInvoker(env, cif, func->fnptr, invocationArgs, cif->rvalue)
351+
: napiInvoker(env, cif, func->fnptr, invocationArgs, cif->rvalue);
352+
if (!invoked) {
343353
return nullptr;
344354
}
345355
} @catch (NSException* exception) {
@@ -350,6 +360,11 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
350360
return nullptr;
351361
}
352362

363+
napi_value fastResult = nullptr;
364+
if (TryFastConvertEngineReturnValue(env, cif->returnType->kind, cif->rvalue,
365+
&fastResult)) {
366+
return fastResult;
367+
}
353368
return cif->returnType->toJS(env, cif->rvalue, toJSFlags);
354369
}
355370

@@ -431,6 +446,11 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
431446
}
432447
}
433448

449+
napi_value fastResult = nullptr;
450+
if (TryFastConvertEngineReturnValue(env, cif->returnType->kind, rvalue,
451+
&fastResult)) {
452+
return fastResult;
453+
}
434454
return cif->returnType->toJS(env, rvalue, toJSFlags);
435455
}
436456

NativeScript/ffi/ClassMember.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class MethodDescriptor {
3333
uint64_t dispatchId = 0;
3434
void* preparedInvoker = nullptr;
3535
void* napiInvoker = nullptr;
36+
void* engineDirectInvoker = nullptr;
3637
void* v8Invoker = nullptr;
3738
bool nserrorOutSignatureCached = false;
3839
bool nserrorOutSignature = false;

NativeScript/ffi/ClassMember.mm

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ inline bool tryObjCNapiDispatch(napi_env env, Cif* cif, id self, bool classMetho
320320
*didInvoke = false;
321321
}
322322

323-
if (cif == nullptr || cif->signatureHash == 0 || cif->skipGeneratedNapiDispatch) {
323+
if (cif == nullptr || cif->signatureHash == 0) {
324324
return true;
325325
}
326326

@@ -344,23 +344,36 @@ inline bool tryObjCNapiDispatch(napi_env env, Cif* cif, id self, bool classMetho
344344
reinterpret_cast<void*>(lookupObjCPreparedInvoker(descriptor->dispatchId));
345345
descriptor->napiInvoker =
346346
reinterpret_cast<void*>(lookupObjCNapiInvoker(descriptor->dispatchId));
347+
descriptor->engineDirectInvoker =
348+
reinterpret_cast<void*>(lookupObjCEngineDirectInvoker(descriptor->dispatchId));
347349
#ifdef TARGET_ENGINE_V8
348350
descriptor->v8Invoker = reinterpret_cast<void*>(lookupObjCV8Invoker(descriptor->dispatchId));
349351
#endif
350352
descriptor->dispatchLookupCached = true;
351353
}
352354
}
353355

354-
auto invoker = descriptor != nullptr
355-
? reinterpret_cast<ObjCNapiInvoker>(descriptor->napiInvoker)
356-
: lookupObjCNapiInvoker(composeSignatureDispatchId(
357-
cif->signatureHash, SignatureCallKind::ObjCMethod, dispatchFlags));
358-
if (invoker == nullptr) {
356+
ObjCEngineDirectInvoker engineInvoker =
357+
descriptor != nullptr
358+
? reinterpret_cast<ObjCEngineDirectInvoker>(descriptor->engineDirectInvoker)
359+
: lookupObjCEngineDirectInvoker(composeSignatureDispatchId(
360+
cif->signatureHash, SignatureCallKind::ObjCMethod, dispatchFlags));
361+
ObjCNapiInvoker invoker =
362+
engineInvoker == nullptr && !cif->skipGeneratedNapiDispatch
363+
? (descriptor != nullptr
364+
? reinterpret_cast<ObjCNapiInvoker>(descriptor->napiInvoker)
365+
: lookupObjCNapiInvoker(composeSignatureDispatchId(
366+
cif->signatureHash, SignatureCallKind::ObjCMethod, dispatchFlags)))
367+
: nullptr;
368+
if (engineInvoker == nullptr && invoker == nullptr) {
359369
return true;
360370
}
361371

362372
@try {
363-
if (!invoker(env, cif, (void*)objc_msgSend, self, selector, argv, rvalue)) {
373+
bool invoked = engineInvoker != nullptr
374+
? engineInvoker(env, cif, (void*)objc_msgSend, self, selector, argv, rvalue)
375+
: invoker(env, cif, (void*)objc_msgSend, self, selector, argv, rvalue);
376+
if (!invoked) {
364377
return false;
365378
}
366379
} @catch (NSException* exception) {
@@ -419,6 +432,8 @@ inline bool objcNativeCall(napi_env env, Cif* cif, id self, bool classMethod,
419432
reinterpret_cast<void*>(lookupObjCPreparedInvoker(descriptor->dispatchId));
420433
descriptor->napiInvoker =
421434
reinterpret_cast<void*>(lookupObjCNapiInvoker(descriptor->dispatchId));
435+
descriptor->engineDirectInvoker =
436+
reinterpret_cast<void*>(lookupObjCEngineDirectInvoker(descriptor->dispatchId));
422437
#ifdef TARGET_ENGINE_V8
423438
descriptor->v8Invoker =
424439
reinterpret_cast<void*>(lookupObjCV8Invoker(descriptor->dispatchId));
@@ -1675,7 +1690,13 @@ explicit CifReturnStorage(Cif* cif) {
16751690
}
16761691
}
16771692

1678-
return cif->returnType->toJS(env, nativeResult, method->returnOwned ? kReturnOwned : 0);
1693+
napi_value fastResult = nullptr;
1694+
if (TryFastConvertEngineReturnValue(env, cif->returnType->kind,
1695+
nativeResult, &fastResult)) {
1696+
return fastResult;
1697+
}
1698+
return cif->returnType->toJS(env, nativeResult,
1699+
method->returnOwned ? kReturnOwned : 0);
16791700
};
16801701

16811702
bool usesBlockFallback = false;
@@ -1867,6 +1888,11 @@ NativeScriptException nativeScriptException(errorMessage != nullptr ? errorMessa
18671888
method->returnOwned ? kOwnedObject : kUnownedObject);
18681889
}
18691890

1891+
napi_value fastResult = nullptr;
1892+
if (TryFastConvertEngineReturnValue(env, cif->returnType->kind, rvalue,
1893+
&fastResult)) {
1894+
return fastResult;
1895+
}
18701896
return cif->returnType->toJS(env, rvalue, 0);
18711897
}
18721898

0 commit comments

Comments
 (0)