Skip to content

Commit 7d24b3e

Browse files
committed
Implement Process module and Node API enhancements
- Added Process.h to define the Process class with methods for CWD, CHDIR, UPTIME, and HRTIME. - Created a CJS module for testing with a simple export. - Introduced .gitignore for ignoring dynamic libraries in node_api tests. - Developed addon.cpp to implement various Node API functionalities including callbacks, threadsafe functions, and error handling. - Added build script for compiling the addon into a dynamic library. - Created cleanup_teardown.js to register teardown hooks and validate cleanup operations. - Implemented reentry_tsfn.js to test callback reentry and threadsafe function behavior. - Added run_teardown_test.sh to automate the testing of cleanup hooks. - Introduced SignatureDispatchEmitter for generating signature dispatch bindings in metadata generation.
1 parent 6fc681d commit 7d24b3e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+3308
-182
lines changed

NativeScript/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ if(ENABLE_JS_RUNTIME)
154154
runtime/modules/node/Node.cpp
155155
runtime/modules/node/FS.cpp
156156
runtime/modules/node/Path.cpp
157+
runtime/modules/node/Process.cpp
157158
runtime/modules/performance/Performance.cpp
159+
runtime/ThreadSafeFunction.mm
158160
runtime/Bundle.mm
159161
runtime/modules/timers/Timers.mm
160162
runtime/modules/app/App.mm

NativeScript/cli/main.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ void bootFromModuleSpec(std::string baseDir, std::string spec) {
6161

6262
int main(int argc, char** argv) {
6363
RuntimeConfig.LogToSystemConsole = true;
64+
RuntimeConfig.Arguments.clear();
65+
if (argv != nullptr && argc > 0) {
66+
RuntimeConfig.Arguments.reserve(static_cast<size_t>(argc));
67+
for (int i = 0; i < argc; i++) {
68+
RuntimeConfig.Arguments.emplace_back(argv[i] != nullptr ? argv[i] : "");
69+
}
70+
}
6471

6572
#ifdef __APPLE__
6673
std::string bytecodePath = getBytecodePathFromBundle();

NativeScript/ffi/CFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef C_FUNCTION_H
22
#define C_FUNCTION_H
33

4+
#include <cstdint>
45
#include "Cif.h"
56

67
namespace nativescript {
@@ -14,6 +15,7 @@ class CFunction {
1415

1516
void* fnptr;
1617
Cif* cif = nullptr;
18+
uint8_t dispatchFlags = 0;
1719
};
1820

1921
} // namespace nativescript

NativeScript/ffi/CFunction.mm

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "CFunction.h"
22
#include "ClassMember.h"
33
#include "ObjCBridge.h"
4+
#include "SignatureDispatch.h"
45
#include "ffi/NativeScriptException.h"
56
#include "ffi/Tasks.h"
67
#include <cstring>
@@ -41,9 +42,11 @@
4142

4243
auto sigOffset =
4344
metadata->signaturesOffset + metadata->getOffset(offset + sizeof(MDSectionOffset));
45+
MDFunctionFlag functionFlags = metadata->getFunctionFlag(offset + sizeof(MDSectionOffset) * 2);
4446

4547
auto cFunction = new CFunction(dlsym(self_dl, metadata->getString(offset)));
4648
cFunction->cif = getCFunctionCif(env, sigOffset);
49+
cFunction->dispatchFlags = (functionFlags & mdFunctionReturnOwned) != 0 ? 1 : 0;
4750
cFunctionCache[offset] = cFunction;
4851

4952
return cFunction;
@@ -63,6 +66,16 @@
6366

6467
auto cif = func->cif;
6568

69+
const uint64_t dispatchId =
70+
cif != nullptr && cif->signatureHash != 0
71+
? composeSignatureDispatchId(cif->signatureHash, SignatureCallKind::CFunction,
72+
func->dispatchFlags)
73+
: 0;
74+
auto invoker = dispatchId != 0 ? lookupCFunctionPreparedInvoker(dispatchId) : nullptr;
75+
76+
MDFunctionFlag functionFlags = bridgeState->metadata->getFunctionFlag(
77+
offset + sizeof(MDSectionOffset) * 2);
78+
6679
size_t argc = cif->argc;
6780
napi_get_cb_info(env, cbinfo, &argc, cif->argv, nullptr, nullptr);
6881

@@ -85,13 +98,17 @@
8598
void** avaluesPtr = new void*[cif->argc];
8699
memcpy(avaluesPtr, avalues, cif->argc * sizeof(void*));
87100

88-
Tasks::Register([env, cif, func, rvalue, avaluesPtr]() {
101+
Tasks::Register([env, cif, func, invoker, rvalue, avaluesPtr]() {
89102
void* avalues[cif->argc];
90103
memcpy(avalues, avaluesPtr, cif->argc * sizeof(void*));
91104
delete[] avaluesPtr;
92105

93106
@try {
94-
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
107+
if (invoker != nullptr) {
108+
invoker(func->fnptr, avalues, rvalue);
109+
} else {
110+
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
111+
}
95112
} @catch (NSException* exception) {
96113
NapiScope scope(env);
97114
std::string message = exception.description.UTF8String;
@@ -106,7 +123,11 @@
106123
#endif
107124

108125
@try {
109-
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
126+
if (invoker != nullptr) {
127+
invoker(func->fnptr, avalues, rvalue);
128+
} else {
129+
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
130+
}
110131
} @catch (NSException* exception) {
111132
std::string message = exception.description.UTF8String;
112133
NSLog(@"ObjC->JS: Exception in CFunction: %s", message.c_str());
@@ -135,8 +156,6 @@
135156
}
136157
}
137158

138-
MDFunctionFlag functionFlags = bridgeState->metadata->getFunctionFlag(
139-
offset + sizeof(MDSectionOffset) * 2);
140159
uint32_t toJSFlags = kCStringAsReference;
141160
if ((functionFlags & mdFunctionReturnOwned) != 0) {
142161
toJSFlags |= kReturnOwned;

NativeScript/ffi/Cif.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef METHOD_CIF_H
22
#define METHOD_CIF_H
33

4+
#include <cstdint>
45
#include <string>
56

67
#include "MetadataReader.h"
@@ -18,6 +19,7 @@ class Cif {
1819
size_t frameLength;
1920
size_t rvalueLength;
2021
bool isVariadic = false;
22+
uint64_t signatureHash = 0;
2123

2224
void* rvalue;
2325
void** avalues;

NativeScript/ffi/Cif.mm

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111
#include "Util.h"
1212

1313
namespace nativescript {
14+
namespace {
15+
16+
constexpr uint64_t kFNV64OffsetBasis = 14695981039346656037ull;
17+
constexpr uint64_t kFNV64Prime = 1099511628211ull;
18+
19+
uint64_t hashBytesFnv1a(const void* data, size_t size) {
20+
const auto* bytes = static_cast<const uint8_t*>(data);
21+
uint64_t hash = kFNV64OffsetBasis;
22+
for (size_t i = 0; i < size; i++) {
23+
hash ^= static_cast<uint64_t>(bytes[i]);
24+
hash *= kFNV64Prime;
25+
}
26+
return hash;
27+
}
28+
29+
} // namespace
1430

1531
// Essentially, we cache libffi structures per unique method signature,
1632
// this helps us avoid the overhead of creating them on the fly for each
@@ -180,6 +196,7 @@
180196

181197
Cif::Cif(napi_env env, MDMetadataReader* reader, MDSectionOffset offset, bool isMethod,
182198
bool isBlock) {
199+
MDSectionOffset signatureStart = offset;
183200
auto returnTypeKind = reader->getTypeKind(offset);
184201
bool next = ((MDTypeFlag)returnTypeKind & mdTypeFlagNext) != 0;
185202
isVariadic = ((MDTypeFlag)returnTypeKind & mdTypeFlagVariadic) != 0;
@@ -249,6 +266,13 @@
249266

250267
rvalue = malloc(cif.rtype->size);
251268
rvalueLength = cif.rtype->size;
269+
270+
const size_t signatureLength = static_cast<size_t>(offset - signatureStart);
271+
if (signatureLength > 0) {
272+
const auto* signatureBytes =
273+
reinterpret_cast<const uint8_t*>(reader->data) + signatureStart;
274+
signatureHash = hashBytesFnv1a(signatureBytes, signatureLength);
275+
}
252276
}
253277

254278
Cif::~Cif() {

NativeScript/ffi/ClassMember.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef BRIDGED_METHOD_H
22
#define BRIDGED_METHOD_H
33

4+
#include <cstdint>
45
#include <iostream>
56
#include <vector>
67

@@ -23,6 +24,7 @@ class MethodDescriptor {
2324
MethodDescriptorKind kind;
2425

2526
MDSectionOffset signatureOffset;
27+
uint8_t dispatchFlags = 0;
2628
std::string encoding;
2729
bool isProperty = false;
2830

@@ -54,8 +56,10 @@ struct ObjCClassMemberOverload {
5456
MethodDescriptor method;
5557
Cif* cif = nullptr;
5658

57-
ObjCClassMemberOverload(SEL selector, MDSectionOffset offset)
58-
: method(selector, offset) {}
59+
ObjCClassMemberOverload(SEL selector, MDSectionOffset offset, uint8_t dispatchFlags)
60+
: method(selector, offset) {
61+
method.dispatchFlags = dispatchFlags;
62+
}
5963
};
6064

6165
class ObjCClassMember {
@@ -69,15 +73,17 @@ class ObjCClassMember {
6973
static napi_value jsGetter(napi_env env, napi_callback_info cbinfo);
7074
static napi_value jsReadOnlySetter(napi_env env, napi_callback_info cbinfo);
7175
static napi_value jsSetter(napi_env env, napi_callback_info cbinfo);
72-
void addOverload(SEL selector, MDSectionOffset offset);
76+
void addOverload(SEL selector, MDSectionOffset offset, uint8_t dispatchFlags);
7377

7478
ObjCClassMember(ObjCBridgeState* bridgeState, SEL selector,
7579
MDSectionOffset offset, MDMemberFlag flags)
7680
: bridgeState(bridgeState),
7781
methodOrGetter(MethodDescriptor(selector, offset)),
7882
returnOwned((flags & metagen::mdMemberReturnOwned) != 0),
7983
classMethod((flags & metagen::mdMemberStatic) != 0),
80-
cls(nullptr) {}
84+
cls(nullptr) {
85+
methodOrGetter.dispatchFlags = returnOwned ? 1 : 0;
86+
}
8187

8288
ObjCClassMember(ObjCBridgeState* bridgeState, SEL getterSelector,
8389
SEL setterSelector, MDSectionOffset getterOffset,
@@ -90,6 +96,8 @@ class ObjCClassMember {
9096
cls(nullptr) {
9197
methodOrGetter.isProperty = true;
9298
setter.isProperty = true;
99+
methodOrGetter.dispatchFlags = returnOwned ? 1 : 0;
100+
setter.dispatchFlags = 0;
93101
}
94102

95103
ObjCBridgeState* bridgeState;

NativeScript/ffi/ClassMember.mm

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "Closure.h"
1414
#include "MetadataReader.h"
1515
#include "ObjCBridge.h"
16+
#include "SignatureDispatch.h"
1617
#include "TypeConv.h"
1718
#include "Util.h"
1819
#include "ffi/Block.h"
@@ -207,7 +208,8 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
207208
if (memberIt->second.methodOrGetter.isProperty) {
208209
continue;
209210
}
210-
memberIt->second.addOverload(methodSelector, signatureOffset);
211+
memberIt->second.addOverload(methodSelector, signatureOffset,
212+
(flags & metagen::mdMemberReturnOwned) != 0 ? 1 : 0);
211213
member = &memberIt->second;
212214
} else if (inheritedProperty && superMember != nullptr &&
213215
!superMember->methodOrGetter.isProperty) {
@@ -216,9 +218,11 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
216218
superMember->methodOrGetter.signatureOffset, flags));
217219
member = &inserted.first->second;
218220
for (const auto& overload : superMember->overloads) {
219-
member->addOverload(overload.method.selector, overload.method.signatureOffset);
221+
member->addOverload(overload.method.selector, overload.method.signatureOffset,
222+
overload.method.dispatchFlags);
220223
}
221-
member->addOverload(methodSelector, signatureOffset);
224+
member->addOverload(methodSelector, signatureOffset,
225+
(flags & metagen::mdMemberReturnOwned) != 0 ? 1 : 0);
222226
} else {
223227
const auto& inserted = memberMap.emplace(
224228
name, ObjCClassMember(bridgeState, methodSelector, signatureOffset, flags));
@@ -269,7 +273,7 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
269273
}
270274
}
271275

272-
void ObjCClassMember::addOverload(SEL selector, MDSectionOffset offset) {
276+
void ObjCClassMember::addOverload(SEL selector, MDSectionOffset offset, uint8_t dispatchFlags) {
273277
if (methodOrGetter.selector == selector) {
274278
return;
275279
}
@@ -280,11 +284,11 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
280284
}
281285
}
282286

283-
overloads.emplace_back(selector, offset);
287+
overloads.emplace_back(selector, offset, dispatchFlags);
284288
}
285289

286-
inline bool objcNativeCall(napi_env env, Cif* cif, id self, bool classMethod, void** avalues,
287-
void* rvalue) {
290+
inline bool objcNativeCall(napi_env env, Cif* cif, id self, bool classMethod, uint8_t dispatchFlags,
291+
void** avalues, void* rvalue) {
288292
SEL selector = avalues != nullptr && cif->cif.nargs >= 2 ? *((SEL*)avalues[1]) : nullptr;
289293

290294
Class receiverClass = nil;
@@ -310,6 +314,16 @@ inline bool objcNativeCall(napi_env env, Cif* cif, id self, bool classMethod, vo
310314

311315
@try {
312316
if (!supercall) {
317+
if (cif != nullptr && cif->signatureHash != 0) {
318+
const uint64_t dispatchId = composeSignatureDispatchId(
319+
cif->signatureHash, SignatureCallKind::ObjCMethod, dispatchFlags);
320+
auto invoker = lookupObjCPreparedInvoker(dispatchId);
321+
if (invoker != nullptr) {
322+
invoker((void*)objc_msgSend, avalues, rvalue);
323+
return true;
324+
}
325+
}
326+
313327
#if defined(__x86_64__)
314328
if (isStret) {
315329
ffi_call(&cif->cif, FFI_FN(objc_msgSend_stret), rvalue, avalues);
@@ -1109,7 +1123,8 @@ size_t getCifArgumentStorageSize(Cif* cif, unsigned int argumentIndex,
11091123
retainedReceiver = true;
11101124
}
11111125

1112-
if (!objcNativeCall(env, cif, self, receiverIsClass, avalues, &rvalue)) {
1126+
if (!objcNativeCall(env, cif, self, receiverIsClass, method->methodOrGetter.dispatchFlags,
1127+
avalues, &rvalue)) {
11131128
if (retainedReceiver) {
11141129
[self release];
11151130
}
@@ -1375,7 +1390,8 @@ size_t getCifArgumentStorageSize(Cif* cif, unsigned int argumentIndex,
13751390

13761391
// NSLog(@"objcNativeCall: %p, %@", self, NSStringFromSelector(method->methodOrGetter.selector));
13771392

1378-
if (!objcNativeCall(env, cif, self, receiverIsClass, avalues, rvalue)) {
1393+
if (!objcNativeCall(env, cif, self, receiverIsClass, selectedMethod->dispatchFlags, avalues,
1394+
rvalue)) {
13791395
for (id block : fallbackBlocksToRelease) {
13801396
[block release];
13811397
}
@@ -1470,7 +1486,8 @@ NativeScriptException nativeScriptException(errorMessage != nullptr ? errorMessa
14701486

14711487
// NSLog(@"objcNativeCall: %p, %@", self, NSStringFromSelector(method->methodOrGetter.selector));
14721488

1473-
if (!objcNativeCall(env, cif, self, receiverIsClass, avalues, rvalue)) {
1489+
if (!objcNativeCall(env, cif, self, receiverIsClass, method->methodOrGetter.dispatchFlags,
1490+
avalues, rvalue)) {
14741491
return nullptr;
14751492
}
14761493

@@ -1534,7 +1551,8 @@ NativeScriptException nativeScriptException(errorMessage != nullptr ? errorMessa
15341551
bool shouldFree = false;
15351552
cif->argTypes[0]->toNative(env, argv, avalues[2], &shouldFree, &shouldFree);
15361553

1537-
if (!objcNativeCall(env, cif, self, receiverIsClass, avalues, rvalue)) {
1554+
if (!objcNativeCall(env, cif, self, receiverIsClass, method->setter.dispatchFlags, avalues,
1555+
rvalue)) {
15381556
return nullptr;
15391557
}
15401558

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef NS_GENERATED_SIGNATURE_DISPATCH_INC
2+
#define NS_GENERATED_SIGNATURE_DISPATCH_INC
3+
4+
namespace nativescript {
5+
6+
inline constexpr ObjCDispatchEntry kGeneratedObjCDispatchEntries[] = {
7+
{0, nullptr},
8+
};
9+
inline constexpr CFunctionDispatchEntry kGeneratedCFunctionDispatchEntries[] = {
10+
{0, nullptr},
11+
};
12+
13+
} // namespace nativescript
14+
15+
#endif // NS_GENERATED_SIGNATURE_DISPATCH_INC

0 commit comments

Comments
 (0)