Skip to content

Commit f34fdda

Browse files
committed
Napi lock overhaul
Before, a reference to an environment was "proof" enough of a lock. Now, an explicit lock witness class is used which also means we can carry around additional lock state.
1 parent 33e46bc commit f34fdda

49 files changed

Lines changed: 694 additions & 416 deletions

Some content is hidden

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

packages/auto_js/napi/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ target_sources(${napi_js}
2020
support/environment.cc
2121
support/host.cc
2222
support/initialize.cc
23+
support/lock.cc
2324
transfer/accept.cc
2425
value/array_buffer.cc
2526
value/array.cc
@@ -35,6 +36,7 @@ target_sources(${napi_js}
3536
api/invoke.cc
3637
api/napi_scheduler.h.cc
3738
api/threadsafe_function.cc
39+
api/unmaybe.cc
3840
api/uv_dlib.h.cc
3941
api/uv_handle.cc
4042
api/uv_scheduler.h.cc
@@ -51,6 +53,7 @@ target_sources(${napi_js}
5153
support/error_scope.cc
5254
support/host.h.cc
5355
support/initialize.h.cc
56+
support/lock.h.cc
5457
support/promise.cc
5558
support/string_table.cc
5659
support/utility.cc

packages/auto_js/napi/_module.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export import :handle.local_of;
1111
export import :handle.types;
1212
export import :handle.value_of;
1313
export import :initialize;
14+
export import :lock;
1415
export import :promise;
1516
export import :reference;
1617
export import :remote;

packages/auto_js/napi/api/api.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export import :api.handle_scope;
88
export import :api.invoke;
99
export import :api.napi_scheduler;
1010
export import :api.threadsafe_function;
11+
export import :api.unmaybe;
1112
export import :api.uv_dlib;
1213
export import :api.uv_handle;
1314
export import :api.uv_scheduler;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

packages/auto_js/napi/handle/remote.cc

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export module napi_js:remote;
22
import :environment;
3+
import :lock;
34
import :reference;
45
import std;
56
import util;
@@ -24,14 +25,16 @@ class remote : protected reference_handle {
2425
using unique_remote = std::unique_ptr<remote, util::function_constant<expire>>;
2526

2627
remote() = default;
27-
remote(private_constructor /*private*/, const environment& env, local_of<Tag> value, napi_scheduler scheduler) :
28-
reference_handle{napi_env{env}, napi_value{value}},
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}},
2930
scheduler_{std::move(scheduler)} {}
3031

31-
auto deref(const environment& env) const -> local_of<Tag>;
32+
auto deref(environment_lock_witness lock) const -> local_of<Tag>;
3233

33-
static auto make_shared(remote_handle_environment auto& env, local_of<Tag> value) -> std::shared_ptr<remote>;
34-
static auto make_unique(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote;
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;
3538

3639
private:
3740
napi_scheduler scheduler_;
@@ -44,14 +47,14 @@ using shared_remote = std::shared_ptr<remote<Type>>;
4447
export template <class Type>
4548
using unique_remote = remote<Type>::unique_remote;
4649

47-
export template <class Tag>
48-
auto make_shared_remote(remote_handle_environment auto& env, local_of<Tag> value) -> shared_remote<Tag> {
49-
return remote<Tag>::make_shared(env, value);
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);
5053
}
5154

52-
export template <class Tag>
53-
auto make_unique_remote(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote<Tag> {
54-
return remote<Tag>::make_unique(env, value);
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);
5558
}
5659

5760
// ---
@@ -68,18 +71,20 @@ auto remote<Tag>::expire(remote* ptr) -> void {
6871
}
6972

7073
template <class Tag>
71-
auto remote<Tag>::deref(const environment& env) const -> local_of<Tag> {
72-
return local_of<Tag>::from(get_value(napi_env{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}));
7376
}
7477

7578
template <class Tag>
76-
auto remote<Tag>::make_shared(remote_handle_environment auto& env, local_of<Tag> value) -> std::shared_ptr<remote> {
77-
return std::shared_ptr<remote>{new remote{private_constructor{}, env, value, env.scheduler()}, expire};
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};
7882
}
7983

8084
template <class Tag>
81-
auto remote<Tag>::make_unique(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote {
82-
return unique_remote{new remote{private_constructor{}, env, value, env.scheduler()}};
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()}};
8388
}
8489

8590
} // namespace js::napi

packages/auto_js/napi/handle/value.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
export module napi_js:handle.value_of;
22
import :handle.types;
3+
import :lock;
34
import nodejs;
45
import std;
6+
import v8;
57

68
namespace js::napi {
79

@@ -33,7 +35,7 @@ class value_next : public value_of<typename Tag::tag_type> {
3335
};
3436

3537
// 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.
3739
template <class Tag>
3840
class value_of : public value_specialization<Tag>::type {
3941
public:
@@ -46,14 +48,19 @@ template <>
4648
class value_of<void> : public runtime_handle {
4749
protected:
4850
value_of() = default;
49-
value_of(napi_env env, napi_value value) :
51+
value_of(environment_lock_witness lock, napi_value value) :
5052
runtime_handle{value},
51-
env_{env} {}
53+
env_{lock},
54+
isolate_{lock.isolate()},
55+
context_{lock.context()} {}
5256

5357
[[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_); }
5459

5560
private:
5661
napi_env env_{};
62+
v8::Isolate* isolate_{};
63+
v8::Local<v8::Context> context_;
5764
};
5865

5966
// Deduction guide

0 commit comments

Comments
 (0)