@auto_js/napi 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +4 -0
- package/_module.cc +2 -0
- package/api/api.cc +1 -0
- package/api/callback_info.cc +1 -1
- package/api/napi_scheduler.cc +21 -0
- package/api/napi_scheduler.h.cc +16 -0
- package/api/threadsafe_function.cc +6 -6
- package/api/unmaybe.cc +36 -0
- package/handle/remote.cc +22 -17
- package/handle/value.cc +14 -3
- package/package.json +4 -4
- package/support/callback.cc +52 -48
- package/support/callback_storage.cc +11 -4
- package/support/class_template_storage.cc +6 -5
- package/support/environment.cc +1 -0
- package/support/environment.h.cc +8 -3
- package/support/environment_fwd.cc +4 -2
- package/support/error_scope.cc +11 -5
- package/support/host.cc +43 -5
- package/support/host.h.cc +13 -2
- package/support/initialize.h.cc +3 -1
- package/support/lock.cc +40 -0
- package/support/lock.h.cc +64 -0
- package/support/promise.cc +28 -18
- package/transfer/accept.cc +1 -1
- package/transfer/accept.h.cc +21 -18
- package/transfer/transfer_list.cc +132 -0
- package/transfer/visit.cc +183 -123
- package/value/array.cc +6 -1
- package/value/array.h.cc +8 -3
- package/value/array_buffer.cc +19 -15
- package/value/array_buffer.h.cc +18 -16
- package/value/class.cc +37 -16
- package/value/class.h.cc +5 -4
- package/value/external.cc +7 -7
- package/value/function.cc +15 -15
- package/value/function.h.cc +6 -5
- package/value/object.cc +2 -2
- package/value/object.h.cc +2 -2
- package/value/record.cc +8 -2
- package/value/record.h.cc +8 -2
package/CMakeLists.txt
CHANGED
|
@@ -20,6 +20,7 @@ target_sources(${napi_js}
|
|
|
20
20
|
support/environment.cc
|
|
21
21
|
support/host.cc
|
|
22
22
|
support/initialize.cc
|
|
23
|
+
support/lock.cc
|
|
23
24
|
transfer/accept.cc
|
|
24
25
|
value/array_buffer.cc
|
|
25
26
|
value/array.cc
|
|
@@ -35,6 +36,7 @@ target_sources(${napi_js}
|
|
|
35
36
|
api/invoke.cc
|
|
36
37
|
api/napi_scheduler.h.cc
|
|
37
38
|
api/threadsafe_function.cc
|
|
39
|
+
api/unmaybe.cc
|
|
38
40
|
api/uv_dlib.h.cc
|
|
39
41
|
api/uv_handle.cc
|
|
40
42
|
api/uv_scheduler.h.cc
|
|
@@ -51,10 +53,12 @@ target_sources(${napi_js}
|
|
|
51
53
|
support/error_scope.cc
|
|
52
54
|
support/host.h.cc
|
|
53
55
|
support/initialize.h.cc
|
|
56
|
+
support/lock.h.cc
|
|
54
57
|
support/promise.cc
|
|
55
58
|
support/string_table.cc
|
|
56
59
|
support/utility.cc
|
|
57
60
|
transfer/accept.h.cc
|
|
61
|
+
transfer/transfer_list.cc
|
|
58
62
|
transfer/visit.cc
|
|
59
63
|
value/array_buffer.h.cc
|
|
60
64
|
value/array.h.cc
|
package/_module.cc
CHANGED
|
@@ -11,11 +11,13 @@ export import :handle.local_of;
|
|
|
11
11
|
export import :handle.types;
|
|
12
12
|
export import :handle.value_of;
|
|
13
13
|
export import :initialize;
|
|
14
|
+
export import :lock;
|
|
14
15
|
export import :promise;
|
|
15
16
|
export import :reference;
|
|
16
17
|
export import :remote;
|
|
17
18
|
export import :string_table;
|
|
18
19
|
export import :support.host;
|
|
20
|
+
export import :transfer_list;
|
|
19
21
|
export import :utility;
|
|
20
22
|
export import :value;
|
|
21
23
|
export import :visit;
|
package/api/api.cc
CHANGED
|
@@ -8,6 +8,7 @@ export import :api.handle_scope;
|
|
|
8
8
|
export import :api.invoke;
|
|
9
9
|
export import :api.napi_scheduler;
|
|
10
10
|
export import :api.threadsafe_function;
|
|
11
|
+
export import :api.unmaybe;
|
|
11
12
|
export import :api.uv_dlib;
|
|
12
13
|
export import :api.uv_handle;
|
|
13
14
|
export import :api.uv_scheduler;
|
package/api/callback_info.cc
CHANGED
|
@@ -35,6 +35,6 @@ export struct callback_info : util::non_copyable {
|
|
|
35
35
|
|
|
36
36
|
// Common declaration for `napi_type_tag` by type
|
|
37
37
|
export template <class Type>
|
|
38
|
-
constexpr auto type_tag_for = napi_type_tag{.lower = util::
|
|
38
|
+
constexpr auto type_tag_for = napi_type_tag{.lower = util::type_hash64<Type>, .upper = 0};
|
|
39
39
|
|
|
40
40
|
} // namespace js::napi
|
package/api/napi_scheduler.cc
CHANGED
|
@@ -32,8 +32,29 @@ auto napi_scheduler::increment_ref(node_api_basic_env env) const -> void {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
auto napi_scheduler::make_ref(node_api_basic_env env) const -> ref {
|
|
36
|
+
return ref{env, *this};
|
|
37
|
+
}
|
|
38
|
+
|
|
35
39
|
auto napi_scheduler::storage::operator()(napi_env env, napi_value value, task_type& task) noexcept -> void {
|
|
36
40
|
task(env, value);
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
// napi_scheduler::ref
|
|
44
|
+
napi_scheduler::ref::ref(node_api_basic_env env, napi_scheduler scheduler) :
|
|
45
|
+
scheduler_{std::move(scheduler)} {
|
|
46
|
+
scheduler_.increment_ref(env);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
napi_scheduler::ref::~ref() {
|
|
50
|
+
if (scheduler_) {
|
|
51
|
+
scheduler_(
|
|
52
|
+
[](napi_env env, napi_value /*nothing*/, const napi_scheduler& scheduler) noexcept -> void {
|
|
53
|
+
scheduler.decrement_ref(env);
|
|
54
|
+
},
|
|
55
|
+
scheduler_
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
} // namespace js::napi
|
package/api/napi_scheduler.h.cc
CHANGED
|
@@ -14,6 +14,8 @@ export class napi_scheduler {
|
|
|
14
14
|
using threadsafe_function_type = threadsafe_function_of<storage, task_type>;
|
|
15
15
|
|
|
16
16
|
public:
|
|
17
|
+
class ref;
|
|
18
|
+
|
|
17
19
|
napi_scheduler() = default;
|
|
18
20
|
explicit napi_scheduler(napi_env env);
|
|
19
21
|
auto operator()(auto task, auto&&... args) const noexcept -> bool;
|
|
@@ -21,6 +23,7 @@ export class napi_scheduler {
|
|
|
21
23
|
auto close(threadsafe_function_type::close_callback close) noexcept -> void;
|
|
22
24
|
auto decrement_ref(node_api_basic_env env) const -> void;
|
|
23
25
|
auto increment_ref(node_api_basic_env env) const -> void;
|
|
26
|
+
auto make_ref(node_api_basic_env env) const -> ref;
|
|
24
27
|
|
|
25
28
|
private:
|
|
26
29
|
struct storage {
|
|
@@ -32,6 +35,19 @@ export class napi_scheduler {
|
|
|
32
35
|
threadsafe_function_of<storage, task_type> fn_;
|
|
33
36
|
};
|
|
34
37
|
|
|
38
|
+
// Reference to a scheduler which keeps the napi event loop alive. Can be passed between threads,
|
|
39
|
+
// the decrement_ref operation is scheduled.
|
|
40
|
+
class napi_scheduler::ref {
|
|
41
|
+
public:
|
|
42
|
+
ref(node_api_basic_env env, napi_scheduler scheduler);
|
|
43
|
+
ref(ref&&) noexcept = default;
|
|
44
|
+
~ref();
|
|
45
|
+
auto operator*() const -> const napi_scheduler& { return scheduler_; }
|
|
46
|
+
|
|
47
|
+
private:
|
|
48
|
+
napi_scheduler scheduler_;
|
|
49
|
+
};
|
|
50
|
+
|
|
35
51
|
// An environment with an uv loop and scheduler
|
|
36
52
|
export class napi_schedulable {
|
|
37
53
|
public:
|
|
@@ -22,8 +22,8 @@ class threadsafe_function_of : util::non_copyable {
|
|
|
22
22
|
auto operator=(threadsafe_function_of&&) -> threadsafe_function_of& = delete;
|
|
23
23
|
|
|
24
24
|
auto close(close_callback callback) noexcept -> void;
|
|
25
|
-
auto ref(node_api_basic_env env) const -> void;
|
|
26
|
-
auto unref(node_api_basic_env env) const -> void;
|
|
25
|
+
auto ref(node_api_basic_env env) const noexcept -> void;
|
|
26
|
+
auto unref(node_api_basic_env env) const noexcept -> void;
|
|
27
27
|
auto operator()(Message message) const noexcept -> bool;
|
|
28
28
|
auto operator*() const noexcept -> Context& { return get(); }
|
|
29
29
|
explicit operator bool() const noexcept { return tsfn_ != nullptr; }
|
|
@@ -103,13 +103,13 @@ auto threadsafe_function_of<Context, Message>::close(close_callback callback) no
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
template <class Context, class Message>
|
|
106
|
-
auto threadsafe_function_of<Context, Message>::ref(node_api_basic_env env) const -> void {
|
|
107
|
-
napi::
|
|
106
|
+
auto threadsafe_function_of<Context, Message>::ref(node_api_basic_env env) const noexcept -> void {
|
|
107
|
+
napi::invoke0_noexcept(napi_ref_threadsafe_function, env, tsfn_);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
template <class Context, class Message>
|
|
111
|
-
auto threadsafe_function_of<Context, Message>::unref(node_api_basic_env env) const -> void {
|
|
112
|
-
napi::
|
|
111
|
+
auto threadsafe_function_of<Context, Message>::unref(node_api_basic_env env) const noexcept -> void {
|
|
112
|
+
napi::invoke0_noexcept(napi_unref_threadsafe_function, env, tsfn_);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
template <class Context, class Message>
|
package/api/unmaybe.cc
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export module napi_js:api.unmaybe;
|
|
2
|
+
import std;
|
|
3
|
+
import v8;
|
|
4
|
+
|
|
5
|
+
namespace js::napi {
|
|
6
|
+
|
|
7
|
+
// Thrown from `unmaybe` to indicate that a direct v8 operation failed and there is an exception
|
|
8
|
+
// waiting in the `v8::TryCatch` of the enclosing `environment_try_catch`.
|
|
9
|
+
export class pending_v8_error : public std::exception {
|
|
10
|
+
public:
|
|
11
|
+
[[nodiscard]] auto what() const noexcept -> const char* final { return "[pending v8 error]"; }
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Unwrap a `MaybeLocal`, or throw `napi::pending_v8_error` on failure
|
|
15
|
+
export template <class Type>
|
|
16
|
+
auto unmaybe(v8::MaybeLocal<Type> maybe_value) -> v8::Local<Type> {
|
|
17
|
+
v8::Local<Type> value;
|
|
18
|
+
if (maybe_value.ToLocal(&value)) {
|
|
19
|
+
return value;
|
|
20
|
+
} else {
|
|
21
|
+
throw napi::pending_v8_error{};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Unwrap a `Maybe`, or throw `napi::pending_v8_error` on failure
|
|
26
|
+
export template <class Type>
|
|
27
|
+
auto unmaybe(v8::Maybe<Type> maybe) -> Type {
|
|
28
|
+
Type value;
|
|
29
|
+
if (maybe.To(&value)) {
|
|
30
|
+
return value;
|
|
31
|
+
} else {
|
|
32
|
+
throw napi::pending_v8_error{};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace js::napi
|
package/handle/remote.cc
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export module napi_js:remote;
|
|
2
2
|
import :environment;
|
|
3
|
+
import :lock;
|
|
3
4
|
import :reference;
|
|
4
5
|
import std;
|
|
5
6
|
import util;
|
|
@@ -24,14 +25,16 @@ class remote : protected reference_handle {
|
|
|
24
25
|
using unique_remote = std::unique_ptr<remote, util::function_constant<expire>>;
|
|
25
26
|
|
|
26
27
|
remote() = default;
|
|
27
|
-
remote(private_constructor /*private*/,
|
|
28
|
-
reference_handle{napi_env{
|
|
28
|
+
remote(private_constructor /*private*/, environment_lock_witness lock, local_of<Tag> value, napi_scheduler scheduler) :
|
|
29
|
+
reference_handle{napi_env{lock}, napi_value{value}},
|
|
29
30
|
scheduler_{std::move(scheduler)} {}
|
|
30
31
|
|
|
31
|
-
auto deref(
|
|
32
|
+
auto deref(environment_lock_witness lock) const -> local_of<Tag>;
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
static auto
|
|
34
|
+
template <remote_handle_environment Environment>
|
|
35
|
+
static auto make_shared(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> std::shared_ptr<remote>;
|
|
36
|
+
template <remote_handle_environment Environment>
|
|
37
|
+
static auto make_unique(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> unique_remote;
|
|
35
38
|
|
|
36
39
|
private:
|
|
37
40
|
napi_scheduler scheduler_;
|
|
@@ -44,14 +47,14 @@ using shared_remote = std::shared_ptr<remote<Type>>;
|
|
|
44
47
|
export template <class Type>
|
|
45
48
|
using unique_remote = remote<Type>::unique_remote;
|
|
46
49
|
|
|
47
|
-
export template <class Tag>
|
|
48
|
-
auto make_shared_remote(
|
|
49
|
-
return remote<Tag>::make_shared(
|
|
50
|
+
export template <remote_handle_environment Environment, class Tag>
|
|
51
|
+
auto make_shared_remote(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> shared_remote<Tag> {
|
|
52
|
+
return remote<Tag>::make_shared(lock, value);
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
export template <class Tag>
|
|
53
|
-
auto make_unique_remote(
|
|
54
|
-
return remote<Tag>::make_unique(
|
|
55
|
+
export template <remote_handle_environment Environment, class Tag>
|
|
56
|
+
auto make_unique_remote(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> unique_remote<Tag> {
|
|
57
|
+
return remote<Tag>::make_unique(lock, value);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
// ---
|
|
@@ -68,18 +71,20 @@ auto remote<Tag>::expire(remote* ptr) -> void {
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
template <class Tag>
|
|
71
|
-
auto remote<Tag>::deref(
|
|
72
|
-
return local_of<Tag>::from(get_value(napi_env{
|
|
74
|
+
auto remote<Tag>::deref(environment_lock_witness lock) const -> local_of<Tag> {
|
|
75
|
+
return local_of<Tag>::from(get_value(napi_env{lock}));
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
template <class Tag>
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
template <remote_handle_environment Environment>
|
|
80
|
+
auto remote<Tag>::make_shared(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> std::shared_ptr<remote> {
|
|
81
|
+
return std::shared_ptr<remote>{new remote{private_constructor{}, lock, value, lock->scheduler()}, expire};
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
template <class Tag>
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
template <remote_handle_environment Environment>
|
|
86
|
+
auto remote<Tag>::make_unique(const environment_lock_witness_of<Environment>& lock, local_of<Tag> value) -> unique_remote {
|
|
87
|
+
return unique_remote{new remote{private_constructor{}, lock, value, lock->scheduler()}};
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
} // namespace js::napi
|
package/handle/value.cc
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export module napi_js:handle.value_of;
|
|
2
2
|
import :handle.types;
|
|
3
|
+
import :lock;
|
|
3
4
|
import nodejs;
|
|
4
5
|
import std;
|
|
6
|
+
import v8;
|
|
5
7
|
|
|
6
8
|
namespace js::napi {
|
|
7
9
|
|
|
@@ -33,7 +35,7 @@ class value_next : public value_of<typename Tag::tag_type> {
|
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
// Member & method implementation for value semantics objects. It holds the type-erased environment
|
|
36
|
-
// and is used for common operations like casting & iteration.
|
|
38
|
+
// lock witness and is used for common operations like casting & iteration.
|
|
37
39
|
template <class Tag>
|
|
38
40
|
class value_of : public value_specialization<Tag>::type {
|
|
39
41
|
public:
|
|
@@ -46,14 +48,19 @@ template <>
|
|
|
46
48
|
class value_of<void> : public runtime_handle {
|
|
47
49
|
protected:
|
|
48
50
|
value_of() = default;
|
|
49
|
-
value_of(
|
|
51
|
+
value_of(environment_lock_witness lock, napi_value value) :
|
|
50
52
|
runtime_handle{value},
|
|
51
|
-
env_{
|
|
53
|
+
env_{lock},
|
|
54
|
+
isolate_{lock.isolate()},
|
|
55
|
+
context_{lock.context()} {}
|
|
52
56
|
|
|
53
57
|
[[nodiscard]] auto env() const -> napi_env { return env_; }
|
|
58
|
+
[[nodiscard]] auto lock() const -> environment_lock_witness { return environment_lock_witness::make_witness(env_, isolate_, context_); }
|
|
54
59
|
|
|
55
60
|
private:
|
|
56
61
|
napi_env env_{};
|
|
62
|
+
v8::Isolate* isolate_{};
|
|
63
|
+
v8::Local<v8::Context> context_;
|
|
57
64
|
};
|
|
58
65
|
|
|
59
66
|
// Deduction guide
|
|
@@ -108,6 +115,10 @@ template <>
|
|
|
108
115
|
struct value_specialization<record_tag>
|
|
109
116
|
: std::type_identity<class value_for_record> {};
|
|
110
117
|
|
|
118
|
+
template <>
|
|
119
|
+
struct value_specialization<list_tag>
|
|
120
|
+
: std::type_identity<class value_for_list> {};
|
|
121
|
+
|
|
111
122
|
template <>
|
|
112
123
|
struct value_specialization<data_block_tag>
|
|
113
124
|
: std::type_identity<class value_for_data_block> {};
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auto_js/napi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"author": "https://github.com/laverdet/",
|
|
5
5
|
"description": "Automatic JavaScript to N-API bindings",
|
|
6
6
|
"homepage": "https://github.com/laverdet/isolated-vm/tree/experimental/packages/auto_js/napi",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@auto_js/js": "^0.0.
|
|
10
|
-
"@auto_js/napi_exports": "^0.0.
|
|
11
|
-
"@auto_js/v8_exports": "^0.0.
|
|
9
|
+
"@auto_js/js": "^0.0.12",
|
|
10
|
+
"@auto_js/napi_exports": "^0.0.11",
|
|
11
|
+
"@auto_js/v8_exports": "^0.0.9"
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
package/support/callback.cc
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export module napi_js:callback;
|
|
2
2
|
export import :callback_storage;
|
|
3
3
|
import :error_scope;
|
|
4
|
+
import :lock;
|
|
4
5
|
import std;
|
|
5
6
|
import util;
|
|
6
7
|
|
|
@@ -10,15 +11,15 @@ namespace js::napi {
|
|
|
10
11
|
// and there is a napi exception pending. `nullptr` will not be returned.
|
|
11
12
|
template <class Type>
|
|
12
13
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
|
13
|
-
constexpr auto unwrap_member_this = [](
|
|
14
|
-
return napi::invoke_maybe(napi_coerce_to_object, napi_env{
|
|
15
|
-
.and_then([ &
|
|
16
|
-
auto as_object = value_of{
|
|
14
|
+
constexpr auto unwrap_member_this = [](environment_lock_witness lock, napi_value this_arg) noexcept -> std::optional<tagged_external<Type>> {
|
|
15
|
+
return napi::invoke_maybe(napi_coerce_to_object, napi_env{lock}, this_arg)
|
|
16
|
+
.and_then([ & ](napi_value coerced_this_arg) -> std::optional<tagged_external<Type>> {
|
|
17
|
+
auto as_object = value_of{lock, local_of<object_tag>::from(coerced_this_arg)};
|
|
17
18
|
// Technically `try_cast` can throw but it should only be in catastrophic cases.
|
|
18
19
|
Type* unwrapped = as_object.try_cast(type<Type>);
|
|
19
20
|
if (unwrapped == nullptr) {
|
|
20
21
|
// nb: The failure here is "no tag" which means we need to set the napi exception
|
|
21
|
-
napi::invoke0(napi_throw_type_error, napi_env{
|
|
22
|
+
napi::invoke0(napi_throw_type_error, napi_env{lock}, nullptr, "Invalid object type");
|
|
22
23
|
return std::nullopt;
|
|
23
24
|
} else {
|
|
24
25
|
return tagged_external{*unwrapped};
|
|
@@ -32,6 +33,7 @@ using internal_constructor = util::function_ref<auto(napi_value)->napi_value>;
|
|
|
32
33
|
// Make callback for plain free function
|
|
33
34
|
template <auto_environment Environment>
|
|
34
35
|
constexpr auto make_free_function(auto function) {
|
|
36
|
+
using lock_type = environment_lock_witness_of<Environment>;
|
|
35
37
|
constexpr auto make_with_try_catch =
|
|
36
38
|
[]<class Env, class... Args, bool Nx, class Result>(
|
|
37
39
|
std::type_identity<auto(Env, Args...) noexcept(Nx)->Result> /*signature*/,
|
|
@@ -39,18 +41,18 @@ constexpr auto make_free_function(auto function) {
|
|
|
39
41
|
) -> auto {
|
|
40
42
|
using callback_type = decltype(callback);
|
|
41
43
|
return util::bind{
|
|
42
|
-
[](callback_type& callback,
|
|
43
|
-
return invoke_internal_error_scope(
|
|
44
|
+
[](callback_type& callback, const lock_type& lock, const callback_info& info) noexcept(Nx) -> napi_value {
|
|
45
|
+
return invoke_internal_error_scope(lock, [ & ] -> napi_value {
|
|
44
46
|
auto run = util::regular_return{[ & ] -> decltype(auto) {
|
|
45
47
|
return std::apply(
|
|
46
48
|
callback,
|
|
47
49
|
std::tuple_cat(
|
|
48
|
-
std::forward_as_tuple(
|
|
49
|
-
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(),
|
|
50
|
+
std::forward_as_tuple(lock),
|
|
51
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), lock)
|
|
50
52
|
)
|
|
51
53
|
);
|
|
52
54
|
}};
|
|
53
|
-
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}),
|
|
55
|
+
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}), lock);
|
|
54
56
|
});
|
|
55
57
|
},
|
|
56
58
|
std::move(callback),
|
|
@@ -64,17 +66,17 @@ constexpr auto make_free_function(auto function) {
|
|
|
64
66
|
static_assert(false, "untested");
|
|
65
67
|
using callback_type = decltype(callback);
|
|
66
68
|
return util::bind{
|
|
67
|
-
[](callback_type& callback,
|
|
69
|
+
[](callback_type& callback, const lock_type& lock, const callback_info& /*info*/) noexcept -> napi_value {
|
|
68
70
|
auto run = util::regular_return{[ & ] -> decltype(auto) {
|
|
69
|
-
return callback(
|
|
71
|
+
return callback(lock);
|
|
70
72
|
}};
|
|
71
|
-
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}),
|
|
73
|
+
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}), lock);
|
|
72
74
|
},
|
|
73
75
|
std::move(callback),
|
|
74
76
|
};
|
|
75
77
|
};
|
|
76
78
|
|
|
77
|
-
auto callback = js::functional::thunk_free_function<
|
|
79
|
+
auto callback = js::functional::thunk_free_function<const lock_type&>(std::move(function));
|
|
78
80
|
constexpr auto make = util::overloaded{make_with_try_catch, make_noexcept};
|
|
79
81
|
return make(std::type_identity<util::function_signature_t<decltype(callback)>>{}, std::move(callback));
|
|
80
82
|
}
|
|
@@ -82,22 +84,23 @@ constexpr auto make_free_function(auto function) {
|
|
|
82
84
|
// Make callback for constructor invocations
|
|
83
85
|
template <auto_environment Environment, class Type>
|
|
84
86
|
constexpr auto make_constructor_function(auto constructor) {
|
|
87
|
+
using lock_type = environment_lock_witness_of<Environment>;
|
|
85
88
|
// First, a lambda is created which will actually invoke the supplied constructor function.
|
|
86
89
|
constexpr auto make_invoke_runtime_constructor = util::overloaded{
|
|
87
90
|
[](std::nullptr_t /*constructor*/) -> auto {
|
|
88
|
-
return [](
|
|
89
|
-
napi::invoke0(napi_throw_type_error, napi_env{
|
|
91
|
+
return [](const lock_type& lock, const callback_info& /*info*/) -> napi_value {
|
|
92
|
+
napi::invoke0(napi_throw_type_error, napi_env{lock}, nullptr, "Illegal constructor");
|
|
90
93
|
return {};
|
|
91
94
|
};
|
|
92
95
|
},
|
|
93
96
|
[](auto constructor) -> auto {
|
|
94
97
|
// These are the last steps, common to both branches
|
|
95
|
-
constexpr auto wrap = [](auto instance,
|
|
98
|
+
constexpr auto wrap = [](auto instance, const lock_type& lock, const callback_info& info) -> napi_value {
|
|
96
99
|
// Tag the result
|
|
97
|
-
napi::invoke0(napi_type_tag_object, napi_env{
|
|
100
|
+
napi::invoke0(napi_type_tag_object, napi_env{lock}, info.this_arg(), &type_tag_for<Type>);
|
|
98
101
|
// Wrap w/ finalizer
|
|
99
102
|
return apply_finalizer(std::move(instance), [ & ](Type* instance, node_api_basic_finalize finalize, void* hint) -> napi_value {
|
|
100
|
-
napi::invoke0(napi_wrap, napi_env{
|
|
103
|
+
napi::invoke0(napi_wrap, napi_env{lock}, info.this_arg(), instance, finalize, hint, nullptr);
|
|
101
104
|
return info.this_arg();
|
|
102
105
|
});
|
|
103
106
|
};
|
|
@@ -111,16 +114,16 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
111
114
|
static_assert(false, "untested");
|
|
112
115
|
using callback_type = decltype(callback);
|
|
113
116
|
return util::bind{
|
|
114
|
-
[](callback_type& callback, wrap_type& wrap,
|
|
115
|
-
return invoke_internal_error_scope(
|
|
117
|
+
[](callback_type& callback, wrap_type& wrap, const lock_type& lock, const callback_info& info) noexcept(Nx) -> napi_value {
|
|
118
|
+
return invoke_internal_error_scope(lock, [ & ] -> napi_value {
|
|
116
119
|
auto instance = std::apply(
|
|
117
120
|
callback,
|
|
118
121
|
std::tuple_cat(
|
|
119
|
-
std::forward_as_tuple(
|
|
120
|
-
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(),
|
|
122
|
+
std::forward_as_tuple(lock, local_of<object_tag>::from(info.this_arg())),
|
|
123
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), lock)
|
|
121
124
|
)
|
|
122
125
|
);
|
|
123
|
-
return wrap(std::move(instance));
|
|
126
|
+
return wrap(std::move(instance), lock, info);
|
|
124
127
|
});
|
|
125
128
|
},
|
|
126
129
|
std::move(callback),
|
|
@@ -135,14 +138,14 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
135
138
|
static_assert(false, "untested");
|
|
136
139
|
using callback_type = decltype(callback);
|
|
137
140
|
return util::bind{
|
|
138
|
-
[](callback_type& callback,
|
|
139
|
-
return wrap(callback(
|
|
141
|
+
[](callback_type& callback, const lock_type& lock, const callback_info& info) noexcept -> napi_value {
|
|
142
|
+
return wrap(callback(lock, local_of<object_tag>::from(info.this_arg())));
|
|
140
143
|
},
|
|
141
144
|
std::move(callback),
|
|
142
145
|
};
|
|
143
146
|
};
|
|
144
147
|
|
|
145
|
-
auto callback = js::functional::thunk_free_function<
|
|
148
|
+
auto callback = js::functional::thunk_free_function<const lock_type&>(std::move(constructor));
|
|
146
149
|
using signature_type = util::function_signature_t<decltype(callback)>;
|
|
147
150
|
static_assert(util::signature_result<signature_type>{} != type<void>);
|
|
148
151
|
constexpr auto make = util::overloaded{make_with_try_catch, make_noexcept};
|
|
@@ -156,18 +159,18 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
156
159
|
// invocation not available to JavaScript. This is done with a tagged external value to a
|
|
157
160
|
// `util::function_ref`.
|
|
158
161
|
return util::bind{
|
|
159
|
-
[](runtime_constructor_type& constructor,
|
|
162
|
+
[](runtime_constructor_type& constructor, const lock_type& lock, const callback_info& info) -> napi_value {
|
|
160
163
|
auto arguments = info.arguments();
|
|
161
164
|
if (!arguments.empty()) {
|
|
162
165
|
auto maybe_constructor = [ & ] -> std::optional<internal_constructor*> {
|
|
163
166
|
try {
|
|
164
167
|
// Check truthiness since null or undefined causes `napi_coerce_to_object` to throw
|
|
165
168
|
auto* arg0 = util::at(arguments, 0);
|
|
166
|
-
if (napi::invoke(napi_coerce_to_bool, napi_env{
|
|
167
|
-
auto* as_object = napi::invoke(napi_coerce_to_object, napi_env{
|
|
168
|
-
auto has_tag = napi::invoke(napi_check_object_type_tag, napi_env{
|
|
169
|
+
if (napi::invoke(napi_coerce_to_bool, napi_env{lock}, arg0)) {
|
|
170
|
+
auto* as_object = napi::invoke(napi_coerce_to_object, napi_env{lock}, arg0);
|
|
171
|
+
auto has_tag = napi::invoke(napi_check_object_type_tag, napi_env{lock}, as_object, &type_tag_for<internal_constructor>);
|
|
169
172
|
if (has_tag) {
|
|
170
|
-
void* addr = napi::invoke(napi_get_value_external, napi_env{
|
|
173
|
+
void* addr = napi::invoke(napi_get_value_external, napi_env{lock}, as_object);
|
|
171
174
|
return static_cast<internal_constructor*>(addr);
|
|
172
175
|
}
|
|
173
176
|
}
|
|
@@ -181,13 +184,13 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
181
184
|
}
|
|
182
185
|
if (*maybe_constructor != nullptr) {
|
|
183
186
|
const auto& constructor = **maybe_constructor;
|
|
184
|
-
return invoke_internal_error_scope(
|
|
187
|
+
return invoke_internal_error_scope(lock, [ & ] -> napi_value {
|
|
185
188
|
return constructor(info.this_arg());
|
|
186
189
|
});
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
// Invoke normal constructor
|
|
190
|
-
return constructor(
|
|
193
|
+
return constructor(lock, info);
|
|
191
194
|
},
|
|
192
195
|
std::move(runtime_constructor),
|
|
193
196
|
};
|
|
@@ -196,6 +199,7 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
196
199
|
// Make callback for method invocations
|
|
197
200
|
template <auto_environment Environment, class Type, class Method>
|
|
198
201
|
constexpr auto make_member_function(Method method) {
|
|
202
|
+
using lock_type = environment_lock_witness_of<Environment>;
|
|
199
203
|
constexpr auto make_with_try_catch =
|
|
200
204
|
[]<class That, class Env, class... Args, bool Nx, class Result>(
|
|
201
205
|
std::type_identity<auto(That, Env, Args...) noexcept(Nx)->Result> /*signature*/,
|
|
@@ -203,22 +207,22 @@ constexpr auto make_member_function(Method method) {
|
|
|
203
207
|
) -> auto {
|
|
204
208
|
using callback_type = decltype(callback);
|
|
205
209
|
return util::bind{
|
|
206
|
-
[](callback_type& callback,
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
[](callback_type& callback, const lock_type& lock, const callback_info& info) noexcept(Nx) -> napi_value {
|
|
211
|
+
return invoke_internal_error_scope(lock, [ & ] -> napi_value {
|
|
212
|
+
auto maybe_that = unwrap_member_this<Type>(lock, info.this_arg());
|
|
213
|
+
if (!maybe_that) {
|
|
214
|
+
return nullptr;
|
|
215
|
+
}
|
|
212
216
|
auto run = util::regular_return{[ & ] -> decltype(auto) {
|
|
213
217
|
return std::apply(
|
|
214
218
|
callback,
|
|
215
219
|
std::tuple_cat(
|
|
216
|
-
std::forward_as_tuple(**maybe_that,
|
|
217
|
-
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(),
|
|
220
|
+
std::forward_as_tuple(**maybe_that, lock),
|
|
221
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), lock)
|
|
218
222
|
)
|
|
219
223
|
);
|
|
220
224
|
}};
|
|
221
|
-
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}),
|
|
225
|
+
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}), lock);
|
|
222
226
|
});
|
|
223
227
|
},
|
|
224
228
|
std::move(callback),
|
|
@@ -232,21 +236,21 @@ constexpr auto make_member_function(Method method) {
|
|
|
232
236
|
static_assert(false, "untested");
|
|
233
237
|
using callback_type = decltype(callback);
|
|
234
238
|
return util::bind{
|
|
235
|
-
[](callback_type& callback,
|
|
236
|
-
auto maybe_that = unwrap_member_this<Type>(
|
|
239
|
+
[](callback_type& callback, const lock_type& lock, const callback_info& info) noexcept -> napi_value {
|
|
240
|
+
auto maybe_that = unwrap_member_this<Type>(lock, info.this_arg());
|
|
237
241
|
if (!maybe_that) {
|
|
238
242
|
return nullptr;
|
|
239
243
|
}
|
|
240
244
|
auto run = util::regular_return{[ & ] -> decltype(auto) {
|
|
241
|
-
return callback(**maybe_that,
|
|
245
|
+
return callback(**maybe_that, lock);
|
|
242
246
|
}};
|
|
243
|
-
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}),
|
|
247
|
+
return js::transfer_in_strict<napi_value>(run().value_or(std::monostate{}), lock);
|
|
244
248
|
},
|
|
245
249
|
std::move(callback),
|
|
246
250
|
};
|
|
247
251
|
};
|
|
248
252
|
|
|
249
|
-
auto callback = js::functional::thunk_member_function<
|
|
253
|
+
auto callback = js::functional::thunk_member_function<const lock_type&>(std::move(method));
|
|
250
254
|
constexpr auto make = util::overloaded{make_with_try_catch, make_noexcept};
|
|
251
255
|
return make(std::type_identity<util::function_signature_t<decltype(callback)>>{}, std::move(callback));
|
|
252
256
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export module napi_js:callback_storage;
|
|
2
2
|
import :api;
|
|
3
3
|
import :environment_fwd;
|
|
4
|
+
import :lock;
|
|
4
5
|
import std;
|
|
5
6
|
|
|
6
7
|
namespace js::napi {
|
|
@@ -15,8 +16,10 @@ thread_local Environment* callback_env_local = nullptr;
|
|
|
15
16
|
// result is a `std::tuple` with `{ callback_ptr, data_ptr, finalizer }`. Finalizer is either a
|
|
16
17
|
// `nullptr` or a `std::unique_ptr<T>` which should be disposed of in a finalizer.
|
|
17
18
|
template <auto_environment Environment>
|
|
18
|
-
auto make_callback_storage(Environment
|
|
19
|
+
auto make_callback_storage(const environment_lock_witness_of<Environment>& lock, std::invocable<const environment_lock_witness_of<Environment>&, const callback_info&> auto function) {
|
|
19
20
|
using function_type = decltype(function);
|
|
21
|
+
using lock_type = environment_lock_witness_of<Environment>;
|
|
22
|
+
auto& env = *lock;
|
|
20
23
|
if constexpr (std::is_trivially_copyable_v<function_type>) {
|
|
21
24
|
if constexpr (std::is_empty_v<function_type>) {
|
|
22
25
|
// Constant expression function, expressed entirely in the type. `data` is the environment.
|
|
@@ -25,7 +28,8 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
25
28
|
if (args) {
|
|
26
29
|
auto invoke = function_type{};
|
|
27
30
|
auto& env = *static_cast<Environment*>(args.data());
|
|
28
|
-
|
|
31
|
+
auto lock = lock_type{environment_lock_witness::make_witness(env), env};
|
|
32
|
+
return invoke(lock, args);
|
|
29
33
|
} else {
|
|
30
34
|
return {};
|
|
31
35
|
}
|
|
@@ -42,7 +46,8 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
42
46
|
auto* data = args.data();
|
|
43
47
|
auto invoke = util::bit_truncation_cast<function_type>(data);
|
|
44
48
|
auto& env = *callback_env_local<Environment>;
|
|
45
|
-
|
|
49
|
+
auto lock = lock_type{environment_lock_witness::make_witness(env), env};
|
|
50
|
+
return invoke(lock, args);
|
|
46
51
|
} else {
|
|
47
52
|
return {};
|
|
48
53
|
}
|
|
@@ -59,7 +64,9 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
59
64
|
const auto args = callback_info{nenv, info};
|
|
60
65
|
if (args) {
|
|
61
66
|
auto& state = *static_cast<pair_type*>(args.data());
|
|
62
|
-
|
|
67
|
+
auto& env = *state.first;
|
|
68
|
+
auto lock = lock_type{environment_lock_witness::make_witness(env), env};
|
|
69
|
+
return state.second(lock, args);
|
|
63
70
|
} else {
|
|
64
71
|
return {};
|
|
65
72
|
}
|