Skip to content

Commit 2872002

Browse files
authored
feat: v8 global reference (#153)
1 parent be77a20 commit 2872002

27 files changed

+1151
-63
lines changed

packages/emnapi/src/core/async-work.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ var emnapiAWMT = {
215215
try {
216216
if (emnapiNodeBinding) {
217217
const resource = emnapiAWMT.getResource(work)
218-
const resource_value = emnapiCtx.getRef(resource)!.get()
218+
const resource_value = emnapiCtx.getRef(resource)!.get(emnapiCtx)
219219
const resourceObject = emnapiCtx.jsValueFromNapiValue(resource_value)!
220220
const view = new DataView(wasmMemory.buffer)
221221
const asyncId = view.getFloat64(work + emnapiAWMT.offset.async_id, true)

packages/emnapi/src/life.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export function napi_get_reference_value (
152152
$CHECK_ARG!(envObject, ref)
153153
$CHECK_ARG!(envObject, result)
154154
const reference = emnapiCtx.getRef(ref)!
155-
const id = reference.get(envObject)
155+
const id = reference.get(emnapiCtx)
156156
from64('result')
157157
makeSetValue('result', 0, 'id', '*')
158158
return envObject.clearLastError()

packages/emnapi/src/threadsafe-function.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ export const emnapiTSFN = {
478478
if (finalize) {
479479
if (emnapiNodeBinding) {
480480
const resource = emnapiTSFN.getResource(func)
481-
const resource_value = emnapiCtx.getRef(resource)!.get()
481+
const resource_value = emnapiCtx.getRef(resource)!.get(emnapiCtx)
482482
const resourceObject = emnapiCtx.jsValueFromNapiValue(resource_value)!
483483
const view = new DataView(wasmMemory.buffer)
484484
const asyncId = view.getFloat64(func + emnapiTSFN.offset.async_id, true)
@@ -567,7 +567,7 @@ export const emnapiTSFN = {
567567
(envObject as NodeEnv).callbackIntoModule(false, () => {
568568
const callJsCb = emnapiTSFN.getCallJSCb(func)
569569
const ref = emnapiTSFN.getRef(func)
570-
const js_callback = ref ? emnapiCtx.getRef(ref)!.get() : 0
570+
const js_callback = ref ? emnapiCtx.getRef(ref)!.get(emnapiCtx) : 0
571571
if (callJsCb) {
572572
const context = emnapiTSFN.getContext(func)
573573
makeDynCall('vpppp', 'callJsCb')(to64('env'), to64('js_callback'), to64('context'), to64('data'))
@@ -583,7 +583,7 @@ export const emnapiTSFN = {
583583
try {
584584
if (emnapiNodeBinding) {
585585
const resource = emnapiTSFN.getResource(func)
586-
const resource_value = emnapiCtx.getRef(resource)!.get()
586+
const resource_value = emnapiCtx.getRef(resource)!.get(emnapiCtx)
587587
const resourceObject = emnapiCtx.jsValueFromNapiValue(resource_value)!
588588
const view = new DataView(wasmMemory.buffer)
589589
emnapiNodeBinding.node.makeCallback(resourceObject, f, [], {

packages/emnapi/src/v8/function.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace v8 {
44

55
extern "C" {
66
V8_EXTERN void _v8_function_set_name(Function* func, internal::Address name);
7+
V8_EXTERN internal::Address _v8_function_new_instance(
8+
const Function* func, Context* context, int argc, internal::Address* argv);
79
}
810

911
void Function::CheckCast(v8::Value*) {}
@@ -12,4 +14,10 @@ void Function::SetName(v8::Local<v8::String> name) {
1214
_v8_function_set_name(this, v8impl::AddressFromV8LocalValue(name));
1315
}
1416

17+
MaybeLocal<Object> Function::NewInstance(
18+
Local<Context> context, int argc, Local<Value> argv[]) const {
19+
return v8impl::V8LocalValueFromAddress(
20+
_v8_function_new_instance(this, *context, argc, reinterpret_cast<internal::Address*>(argv))).As<Object>();
21+
}
22+
1523
}

packages/emnapi/src/v8/function.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { from64, makeGetValue, POINTER_SIZE } from 'emscripten:parse-tools'
2+
13
/**
24
* @__deps $emnapiCtx
35
* @__sig vpp
@@ -10,3 +12,39 @@ export function _v8_function_set_name (fn: Ptr, name: Ptr): void {
1012
const func = emnapiCtx.jsValueFromNapiValue(fn)
1113
emnapiCtx.features.setFunctionName(func, str)
1214
}
15+
16+
/**
17+
* @__deps $emnapiCtx
18+
* @__sig ppppp
19+
*/
20+
export function _v8_function_new_instance (fn: Ptr, ctx: Ptr, argc: number, argv: Ptr): Ptr {
21+
const Ctor = emnapiCtx.jsValueFromNapiValue(fn)
22+
from64('argv')
23+
24+
let i: number
25+
let ret: any
26+
try {
27+
if (emnapiCtx.features.Reflect) {
28+
const argList = Array(argc)
29+
for (i = 0; i < argc; i++) {
30+
const argVal = makeGetValue('argv', 'i * ' + POINTER_SIZE, '*')
31+
argList[i] = emnapiCtx.jsValueFromNapiValue(argVal)!
32+
}
33+
ret = emnapiCtx.features.Reflect.construct(Ctor, argList, Ctor)
34+
} else {
35+
const args = Array(argc + 1) as [undefined, ...any[]]
36+
args[0] = undefined
37+
for (i = 0; i < argc; i++) {
38+
const argVal = makeGetValue('argv', 'i * ' + POINTER_SIZE, '*')
39+
args[i + 1] = emnapiCtx.jsValueFromNapiValue(argVal)!
40+
}
41+
const BoundCtor = Ctor.bind.apply(Ctor, args) as new () => any
42+
ret = new BoundCtor()
43+
}
44+
} catch (err) {
45+
emnapiCtx.throwException(err)
46+
return 1
47+
}
48+
49+
return emnapiCtx.napiValueFromJsValue(ret)
50+
}

packages/emnapi/src/v8/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './exception'
33
export * from './external'
44
export * from './function'
55
export * from './handle_scope'
6+
export * from './internal'
67
export * from './isolate'
78
export * from './number'
89
export * from './object'

packages/emnapi/src/v8/internal.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33

44
namespace v8 {
55

6+
extern "C" {
7+
V8_EXTERN internal::Address _v8_globalize_reference(
8+
internal::Isolate* isolate, internal::Address value);
9+
V8_EXTERN void _v8_dispose_global(internal::Address global_handle);
10+
V8_EXTERN void _v8_make_weak(internal::Address location,
11+
void* data,
12+
void (*callback)(
13+
WeakCallbackInfo<void>::Callback weak_callback,
14+
void* data, WeakCallbackType type,
15+
void* internal_field1, void* internal_field2),
16+
WeakCallbackInfo<void>::Callback weak_callback,
17+
WeakCallbackType type);
18+
V8_EXTERN void* _v8_clear_weak(internal::Address location);
19+
}
20+
621
namespace internal {
722

823
Isolate* IsolateFromNeverReadOnlySpaceObject(unsigned long obj) {
@@ -38,6 +53,47 @@ void FromJustIsNothing() {
3853
abort();
3954
}
4055

56+
internal::Address* GlobalizeReference(internal::Isolate* isolate,
57+
internal::Address value) {
58+
internal::Address ref_id = _v8_globalize_reference(isolate, value);
59+
return new internal::Address(ref_id);
60+
}
61+
62+
void DisposeGlobal(internal::Address* global_handle) {
63+
_v8_dispose_global(*global_handle);
64+
delete global_handle;
65+
}
66+
67+
namespace {
68+
static void WeakCallback(WeakCallbackInfo<void>::Callback weak_callback,
69+
void* data,
70+
WeakCallbackType type,
71+
void* internal_field1,
72+
void* internal_field2) {
73+
void* embedder_fields[kEmbedderFieldsInWeakCallback] = {
74+
internal_field1, internal_field2
75+
};
76+
WeakCallbackInfo<void>::Callback second = nullptr;
77+
WeakCallbackInfo<void> info(
78+
Isolate::GetCurrent(), data,
79+
embedder_fields, &second);
80+
weak_callback(info);
81+
if (second != nullptr) {
82+
second(info);
83+
}
84+
}
85+
}
86+
87+
void MakeWeak(internal::Address* location, void* data,
88+
WeakCallbackInfo<void>::Callback weak_callback,
89+
WeakCallbackType type) {
90+
_v8_make_weak(*location, data, WeakCallback, weak_callback, type);
91+
}
92+
93+
void* ClearWeak(internal::Address* location) {
94+
return _v8_clear_weak(*location);
95+
};
96+
4197
} // namespace api_internal
4298

4399
} // namespace v8

packages/emnapi/src/v8/internal.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { from64, makeDynCall } from 'emscripten:parse-tools'
2+
3+
/**
4+
* @__deps $emnapiCtx
5+
* @__sig ppp
6+
*/
7+
export function _v8_globalize_reference (isolate: Ptr, value: Ptr): Ptr {
8+
const jsValue = emnapiCtx.jsValueFromNapiValue(value)
9+
if (jsValue === undefined) return 0
10+
return emnapiCtx.createReference(undefined, jsValue, 1, ReferenceOwnership.kUserland as any).id
11+
}
12+
13+
/**
14+
* @__deps $emnapiCtx
15+
* @__sig vp
16+
*/
17+
export function _v8_dispose_global (ref: Ptr): void {
18+
const refValue = emnapiCtx.getRef(ref)
19+
if (!refValue) return
20+
refValue.dispose()
21+
}
22+
23+
/**
24+
* @__deps $emnapiCtx
25+
* @__sig vppppi
26+
*/
27+
export function _v8_make_weak (ref: Ptr, data: Ptr, callback: Ptr, weak_callback: Ptr, type: number): void {
28+
const refValue = emnapiCtx.getRef(ref)
29+
if (!refValue) return
30+
from64('callback')
31+
refValue.setWeakWithData(data, (data) => {
32+
let field0 = 0
33+
let field1 = 0
34+
if (type === 1) {
35+
const id = refValue.get(emnapiCtx)
36+
if (id) {
37+
const value = emnapiCtx.jsValueFromNapiValue(id)
38+
field0 = emnapiCtx.getInternalField(value, 0)
39+
field1 = emnapiCtx.getInternalField(value, 1)
40+
if ((typeof field0 !== 'number' && typeof field0 !== 'bigint') ||
41+
(typeof field1 !== 'number' && typeof field1 !== 'bigint')) {
42+
throw new Error('Internal field is not a number')
43+
}
44+
}
45+
}
46+
makeDynCall('vppipp', 'callback')(weak_callback, data, type, field0, field1)
47+
})
48+
}
49+
50+
/**
51+
* @__deps $emnapiCtx
52+
* @__sig pp
53+
*/
54+
export function _v8_clear_weak (ref: Ptr): Ptr {
55+
const refValue = emnapiCtx.getRef(ref)
56+
if (!refValue) return 0
57+
refValue.clearWeak()
58+
return 0
59+
}

packages/emnapi/src/v8/object.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ namespace v8 {
55
extern "C" {
66
V8_EXTERN int _v8_object_set(Object* obj, Context* context, internal::Address key, internal::Address value, int* success);
77
V8_EXTERN void _v8_object_set_internal_field(Object* obj, int index, internal::Address data);
8+
V8_EXTERN void _v8_object_set_aligned_pointer_in_internal_field(Object* obj, int index, void* data);
9+
V8_EXTERN void* _v8_object_get_aligned_pointer_in_internal_field(Object* obj, int index);
810
V8_EXTERN internal::Address _v8_object_get_internal_field(Object* obj, int index);
911
V8_EXTERN internal::Address _v8_object_get_key(Object* obj, Context* context, internal::Address index);
1012
V8_EXTERN internal::Address _v8_object_get_index(Object* obj, Context* context, uint32_t index);
13+
V8_EXTERN int _v8_object_internal_field_count(const Object* obj);
1114
}
1215

1316
void Object::CheckCast(v8::Value*) {}
@@ -35,6 +38,18 @@ void Object::SetInternalField(int index, v8::Local<v8::Data> data) {
3538
_v8_object_set_internal_field(this, index, reinterpret_cast<internal::Address>(*data));
3639
}
3740

41+
void Object::SetAlignedPointerInInternalField(int index, void* data) {
42+
_v8_object_set_aligned_pointer_in_internal_field(this, index, data);
43+
}
44+
45+
void* Object::SlowGetAlignedPointerFromInternalField(int index) {
46+
return _v8_object_get_aligned_pointer_in_internal_field(this, index);
47+
}
48+
49+
int Object::InternalFieldCount() const {
50+
return _v8_object_internal_field_count(this);
51+
}
52+
3853
Local<Data> Object::SlowGetInternalField(int index) {
3954
internal::Address data_value = _v8_object_get_internal_field(this, index);
4055
Local<Data> data;

packages/emnapi/src/v8/object.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ export function _v8_object_set (obj: Ptr, context: Ptr, key: Ptr, value: Ptr, su
1919
return 0
2020
}
2121

22+
/**
23+
* @__deps $emnapiCtx
24+
* @__sig ip
25+
*/
26+
export function _v8_object_internal_field_count (
27+
obj: Ptr
28+
): number {
29+
const objValue = emnapiCtx.jsValueFromNapiValue(obj)
30+
return emnapiCtx.getInternalFieldCount(objValue)
31+
}
32+
2233
/**
2334
* @__deps $emnapiCtx
2435
* @__sig vpip
@@ -33,6 +44,19 @@ export function _v8_object_set_internal_field (
3344
emnapiCtx.setInternalField(objValue, index, dataValue)
3445
}
3546

47+
/**
48+
* @__deps $emnapiCtx
49+
* @__sig vpip
50+
*/
51+
export function _v8_object_set_aligned_pointer_in_internal_field (
52+
obj: Ptr,
53+
index: number,
54+
data: Ptr
55+
): void {
56+
const objValue = emnapiCtx.jsValueFromNapiValue(obj)
57+
emnapiCtx.setInternalField(objValue, index, data)
58+
}
59+
3660
/**
3761
* @__deps $emnapiCtx
3862
* @__sig pip
@@ -45,6 +69,18 @@ export function _v8_object_get_internal_field (
4569
return emnapiCtx.napiValueFromJsValue(emnapiCtx.getInternalField(objValue, index))
4670
}
4771

72+
/**
73+
* @__deps $emnapiCtx
74+
* @__sig pip
75+
*/
76+
export function _v8_object_get_aligned_pointer_in_internal_field (
77+
obj: Ptr,
78+
index: number
79+
): Ptr {
80+
const objValue = emnapiCtx.jsValueFromNapiValue(obj)
81+
return emnapiCtx.getInternalField(objValue, index)
82+
}
83+
4884
/**
4985
* @__deps $emnapiCtx
5086
* @__sig pppp

0 commit comments

Comments
 (0)