Skip to content

Commit 6748ebd

Browse files
committed
Address comments
1 parent 8d19763 commit 6748ebd

File tree

5 files changed

+55
-43
lines changed

5 files changed

+55
-43
lines changed

crates/core/src/host/v8/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use self::error::{
66
use self::ser::serialize_to_js;
77
use self::string::{str_from_ident, IntoJsString};
88
use self::syscall::{
9-
call_call_reducer, call_describe_module, get_hook, resolve_sys_module, FnRet, HookFunction, ModuleHook,
9+
call_call_reducer, call_describe_module, get_hook, resolve_sys_module, FnRet, HookFunction, ModuleHookKey,
1010
};
1111
use super::module_common::{build_common_module_from_raw, run_describer, ModuleCommon};
1212
use super::module_host::{CallReducerParams, Module, ModuleInfo, ModuleRuntime};
@@ -331,7 +331,7 @@ fn startup_instance_worker<'scope>(
331331

332332
// Find the `__call_reducer__` function.
333333
let call_reducer_fun =
334-
get_hook(scope, ModuleHook::CallReducer).context("The `spacetimedb/server` module was never imported")?;
334+
get_hook(scope, ModuleHookKey::CallReducer).context("The `spacetimedb/server` module was never imported")?;
335335

336336
// If we don't have a module, make one.
337337
let module_common = match module_or_mcc {
@@ -652,7 +652,7 @@ fn extract_description<'scope>(
652652
|a, b, c| log_traceback(replica_ctx, a, b, c),
653653
|| {
654654
catch_exception(scope, |scope| {
655-
let Some(describe_module) = get_hook(scope, ModuleHook::DescribeModule) else {
655+
let Some(describe_module) = get_hook(scope, ModuleHookKey::DescribeModule) else {
656656
return Ok(RawModuleDef::V9(Default::default()));
657657
};
658658
let def = call_describe_module(scope, describe_module)?;
@@ -692,7 +692,7 @@ mod test {
692692
fn call_call_reducer_works() {
693693
let call = |code| {
694694
with_module_catch(code, |scope| {
695-
let fun = get_hook(scope, ModuleHook::CallReducer).unwrap();
695+
let fun = get_hook(scope, ModuleHookKey::CallReducer).unwrap();
696696
let op = ReducerOp {
697697
id: ReducerId(42),
698698
name: "foobar",
@@ -771,7 +771,7 @@ js error Uncaught Error: foobar
771771
})
772772
"#;
773773
let raw_mod = with_module_catch(code, |scope| {
774-
let describe_module = get_hook(scope, ModuleHook::DescribeModule).unwrap();
774+
let describe_module = get_hook(scope, ModuleHookKey::DescribeModule).unwrap();
775775
call_describe_module(scope, describe_module)
776776
})
777777
.map_err(|e| e.to_string());

crates/core/src/host/v8/syscall/hooks.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,67 +28,77 @@ pub(super) fn get_hook_function<'scope>(
2828
pub(super) fn set_hook_slots(
2929
scope: &mut PinScope<'_, '_>,
3030
abi: AbiVersion,
31-
hooks: &[(ModuleHook, Local<'_, Function>)],
31+
hooks: &[(ModuleHookKey, Local<'_, Function>)],
3232
) -> ExcResult<()> {
3333
// Make sure to call `set_slot` first, as it creates the annex
3434
// and `set_embedder_data` is currently buggy.
3535
let ctx = scope.get_current_context();
36-
let hooks_info = HooksInfo::get_or_create(&ctx);
36+
let hooks_info = HooksInfo::get_or_create(&ctx, abi)
37+
.map_err(|_| TypeError("cannot call `register_hooks` from different versions").throw(scope))?;
3738
for &(hook, func) in hooks {
3839
hooks_info
39-
.register(hook, abi)
40+
.register(hook)
4041
.map_err(|_| TypeError("cannot call `register_hooks` multiple times").throw(scope))?;
4142
ctx.set_embedder_data(hook.to_slot_index(), func.into());
4243
}
4344
Ok(())
4445
}
4546

4647
#[derive(enum_map::Enum, Copy, Clone)]
47-
pub(in crate::host::v8) enum ModuleHook {
48+
pub(in super::super) enum ModuleHookKey {
4849
DescribeModule,
4950
CallReducer,
5051
}
5152

52-
impl ModuleHook {
53+
impl ModuleHookKey {
5354
/// Returns the index for the slot that holds the module function hook.
5455
/// The index is passed to `v8::Context::{get,set}_embedder_data`.
5556
fn to_slot_index(self) -> i32 {
5657
match self {
57-
ModuleHook::DescribeModule => 20,
58-
ModuleHook::CallReducer => 21,
58+
// high numbers to avoid overlapping with rusty_v8 - can be
59+
// reverted to just 0, 1... once denoland/rusty_v8#1868 merges
60+
ModuleHookKey::DescribeModule => 20,
61+
ModuleHookKey::CallReducer => 21,
5962
}
6063
}
6164
}
6265

6366
/// Holds the `AbiVersion` used by the module
6467
/// and the module hooks registered by the module
6568
/// for that version.
66-
#[derive(Default)]
6769
struct HooksInfo {
68-
abi: OnceCell<AbiVersion>,
69-
registered: EnumMap<ModuleHook, OnceCell<()>>,
70+
abi: AbiVersion,
71+
registered: EnumMap<ModuleHookKey, OnceCell<()>>,
7072
}
7173

7274
impl HooksInfo {
7375
/// Returns, and possibly creates, the [`HooksInfo`] stored in `ctx`.
74-
fn get_or_create(ctx: &Context) -> Rc<Self> {
75-
ctx.get_slot().unwrap_or_else(|| {
76-
let this = Rc::<Self>::default();
77-
ctx.set_slot(this.clone());
78-
this
79-
})
76+
///
77+
/// Returns an error if `abi` doesn't match the abi version in the
78+
/// already existing `HooksInfo`.
79+
fn get_or_create(ctx: &Context, abi: AbiVersion) -> Result<Rc<Self>, ()> {
80+
match ctx.get_slot::<Self>() {
81+
Some(this) if this.abi == abi => Ok(this),
82+
Some(_) => Err(()),
83+
None => {
84+
let this = Rc::new(Self {
85+
abi,
86+
registered: EnumMap::default(),
87+
});
88+
ctx.set_slot(this.clone());
89+
Ok(this)
90+
}
91+
}
8092
}
8193

82-
fn register(&self, hook: ModuleHook, abi: AbiVersion) -> Result<(), ()> {
83-
if *self.abi.get_or_init(|| abi) != abi {
84-
return Err(());
85-
}
94+
/// Mark down the given `hook` as registered, returning an error if it already was.
95+
fn register(&self, hook: ModuleHookKey) -> Result<(), ()> {
8696
self.registered[hook].set(())
8797
}
8898

8999
/// Returns the `AbiVersion` for the given `hook`, if any.
90-
fn get(&self, hook: ModuleHook) -> Option<AbiVersion> {
91-
self.registered[hook].get().and(self.abi.get().copied())
100+
fn get(&self, hook: ModuleHookKey) -> Option<AbiVersion> {
101+
self.registered[hook].get().map(|_| self.abi)
92102
}
93103
}
94104

@@ -99,7 +109,7 @@ pub(in super::super) struct HookFunction<'scope>(pub AbiVersion, pub Local<'scop
99109
/// Returns the hook function previously registered in [`register_hooks`].
100110
pub(in super::super) fn get_hook<'scope>(
101111
scope: &mut PinScope<'scope, '_>,
102-
hook: ModuleHook,
112+
hook: ModuleHookKey,
103113
) -> Option<HookFunction<'scope>> {
104114
let ctx = scope.get_current_context();
105115
let hooks = ctx.get_slot::<HooksInfo>()?;

crates/core/src/host/v8/syscall/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
use spacetimedb_lib::RawModuleDef;
2+
use spacetimedb_lib::VersionTuple;
23
use v8::{callback_scope, Context, FixedArray, Local, Module, PinScope};
34

45
use crate::host::v8::de::scratch_buf;
56
use crate::host::v8::error::ExcResult;
67
use crate::host::v8::error::Throwable;
78
use crate::host::v8::error::TypeError;
9+
use crate::host::wasm_common::abi::parse_abi_version;
810
use crate::host::wasm_common::module_host_actor::{ReducerOp, ReducerResult};
911

1012
mod hooks;
1113
mod v1;
1214

13-
pub(super) use self::hooks::{get_hook, HookFunction, ModuleHook};
15+
pub(super) use self::hooks::{get_hook, HookFunction, ModuleHookKey};
1416

1517
/// The return type of a module -> host syscall.
1618
pub(super) type FnRet<'scope> = ExcResult<Local<'scope, v8::Value>>;
@@ -47,17 +49,15 @@ fn resolve_sys_module_inner<'scope>(
4749
.and_then(|spec| spec.split_once('@'))
4850
.ok_or_else(|| generic_error().throw(scope))?;
4951

50-
let (maj, min) = ver
51-
.split_once('.')
52-
.and_then(|(maj, min)| Option::zip(maj.parse::<u32>().ok(), min.parse::<u32>().ok()))
52+
let VersionTuple { major, minor } = parse_abi_version(ver)
5353
.ok_or_else(|| TypeError(format!("Invalid version in module spec {spec:?}")).throw(scope))?;
5454

5555
match module {
56-
"sys" => match (maj, min) {
56+
"sys" => match (major, minor) {
5757
(1, 0) => Ok(v1::sys_v1_0(scope)),
5858
_ => Err(TypeError(format!(
5959
"Could not import {spec:?}, likely because this module was built for a newer version of SpacetimeDB.\n\
60-
It requires sys module v{maj}.{min}, but that version is not supported by the database."
60+
It requires sys module v{major}.{minor}, but that version is not supported by the database."
6161
))
6262
.throw(scope)),
6363
},

crates/core/src/host/v8/syscall/v1.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::hooks::{get_hook_function, set_hook_slots};
2-
use super::{AbiVersion, FnRet, ModuleHook};
2+
use super::{AbiVersion, FnRet, ModuleHookKey};
33
use crate::database_logger::{LogLevel, Record};
44
use crate::error::NodesError;
55
use crate::host::instance_env::InstanceEnv;
@@ -323,8 +323,8 @@ fn register_hooks_v1_0<'scope>(scope: &mut PinScope<'scope, '_>, args: FunctionC
323323
scope,
324324
AbiVersion::V1,
325325
&[
326-
(ModuleHook::DescribeModule, describe_module),
327-
(ModuleHook::CallReducer, call_reducer),
326+
(ModuleHookKey::DescribeModule, describe_module),
327+
(ModuleHookKey::CallReducer, call_reducer),
328328
],
329329
)?;
330330

crates/core/src/host/wasm_common/abi.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ pub fn determine_spacetime_abi<I>(
88
) -> Result<VersionTuple, AbiVersionError> {
99
let it = imports.into_iter().filter_map(|imp| {
1010
let s = get_module(&imp);
11-
let err = || AbiVersionError::Parse { module: s.to_owned() };
12-
s.strip_prefix(MODULE_PREFIX).map(|ver| {
13-
let (major, minor) = ver.split_once('.').ok_or_else(err)?;
14-
let (major, minor) = Option::zip(major.parse().ok(), minor.parse().ok()).ok_or_else(err)?;
15-
Ok(VersionTuple { major, minor })
16-
})
11+
s.strip_prefix(MODULE_PREFIX)
12+
.map(|ver| parse_abi_version(ver).ok_or_else(|| AbiVersionError::Parse { module: s.to_owned() }))
1713
});
1814
itertools::process_results(it, |mut it| {
1915
let first = it.next().ok_or(AbiVersionError::NotDetected)?;
2016
it.try_fold(first, refine_ver_req)
2117
})?
2218
}
2319

20+
pub fn parse_abi_version(ver: &str) -> Option<VersionTuple> {
21+
let (major, minor) = ver.split_once('.')?;
22+
let (major, minor) = Option::zip(major.parse().ok(), minor.parse().ok())?;
23+
Some(VersionTuple { major, minor })
24+
}
25+
2426
fn refine_ver_req(ver: VersionTuple, new: VersionTuple) -> Result<VersionTuple, AbiVersionError> {
2527
if ver.major != new.major {
2628
Err(AbiVersionError::MultipleMajor(ver.major, new.major))

0 commit comments

Comments
 (0)