Skip to content

Commit 8b86570

Browse files
coolreader18Centril
authored andcommitted
wip
switch to sats-based deserialization ModuleInstance impl wip
1 parent 4290500 commit 8b86570

13 files changed

Lines changed: 1725 additions & 9 deletions

File tree

.prettierrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"tabWidth": 4,
3+
"useTabs": false,
4+
"semi": true,
5+
"singleQuote": true,
6+
"arrowParens": "avoid",
7+
"jsxSingleQuote": false,
8+
"trailingComma": "es5",
9+
"endOfLine": "auto",
10+
"printWidth": 100
11+
}

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,6 @@ termcolor = "1.2.0"
262262
thin-vec = "0.2.13"
263263
thiserror = "1.0.37"
264264
tokio = { version = "1.37", features = ["full"] }
265-
tokio_metrics = { version = "0.4.0" }
266265
tokio-postgres = { version = "0.7.8", features = ["with-chrono-0_4"] }
267266
tokio-stream = "0.1.17"
268267
tokio-tungstenite = { version = "0.26.2", features = ["native-tls"] }

crates/core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ jwks.workspace = true
118118
async_cache = "0.3.1"
119119
faststr = "0.2.23"
120120
core_affinity = "0.8"
121+
num-traits = "0.2"
122+
# sourcemap = "9"
121123

122124
[target.'cfg(not(target_env = "msvc"))'.dependencies]
123125
tikv-jemallocator = {workspace = true}

crates/core/src/host/v8/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.js

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

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
use std::borrow::Cow;
2+
3+
use spacetimedb_sats::{de, i256, u256};
4+
5+
use super::convert::{cast, FromValue};
6+
use super::util::{scratch_buf, ExceptionOptionExt, ExceptionThrown, IntoExceptionResultExt, Throwable, TypeError};
7+
8+
pub(super) struct Deserializer<'a, 's> {
9+
common: DeserializerCommon<'a, 's>,
10+
input: v8::Local<'s, v8::Value>,
11+
}
12+
13+
impl<'a, 's> Deserializer<'a, 's> {
14+
pub fn new(
15+
scope: &'a mut v8::HandleScope<'s>,
16+
input: v8::Local<'_, v8::Value>,
17+
key_cache: &'a mut KeyCache,
18+
) -> Self {
19+
let input = v8::Local::new(scope, input);
20+
let common = DeserializerCommon { scope, key_cache };
21+
Deserializer { input, common }
22+
}
23+
}
24+
25+
struct DeserializerCommon<'a, 's> {
26+
scope: &'a mut v8::HandleScope<'s>,
27+
key_cache: &'a mut KeyCache,
28+
}
29+
30+
impl<'a, 's> DeserializerCommon<'a, 's> {
31+
fn reborrow(&mut self) -> DeserializerCommon<'_, 's> {
32+
DeserializerCommon {
33+
scope: self.scope,
34+
key_cache: self.key_cache,
35+
}
36+
}
37+
}
38+
39+
macro_rules! def_key_cache {
40+
($($key:ident$(: $string:expr)?),* $(,)?) => {
41+
#[derive(Default)]
42+
pub(super) struct KeyCache {
43+
$($key: Option<v8::Global<v8::String>>,)*
44+
}
45+
impl KeyCache {
46+
$(pub(super) fn $key<'s>(&mut self, scope: &mut v8::HandleScope<'s>) -> v8::Local<'s, v8::String> {
47+
get_or_create_key(scope, &mut self.$key, ($($string,)? stringify!($key),).0)
48+
})*
49+
}
50+
};
51+
}
52+
53+
fn get_or_create_key<'s>(
54+
scope: &mut v8::HandleScope<'s>,
55+
key: &mut Option<v8::Global<v8::String>>,
56+
string: &str,
57+
) -> v8::Local<'s, v8::String> {
58+
if let Some(s) = &*key {
59+
v8::Local::new(scope, s)
60+
} else {
61+
let s = v8_struct_key(scope, string);
62+
*key = Some(v8::Global::new(scope, s));
63+
s
64+
}
65+
}
66+
67+
def_key_cache!(tag, value, some);
68+
69+
// creates an optimized v8::String for a struct field
70+
pub fn v8_struct_key<'s>(scope: &mut v8::HandleScope<'s>, field: &str) -> v8::Local<'s, v8::String> {
71+
// Internalized v8 strings are significantly faster than "normal" v8 strings
72+
// since v8 deduplicates re-used strings minimizing new allocations
73+
// see: https://github.com/v8/v8/blob/14ac92e02cc3db38131a57e75e2392529f405f2f/include/v8.h#L3165-L3171
74+
v8::String::new_from_utf8(scope, field.as_ref(), v8::NewStringType::Internalized).unwrap()
75+
}
76+
77+
pub(super) enum Error<'s> {
78+
Value(v8::Local<'s, v8::Value>),
79+
Exception(ExceptionThrown),
80+
String(String),
81+
}
82+
83+
impl<'s> Throwable for Error<'s> {
84+
fn throw(self, scope: &mut v8::HandleScope<'_>) -> ExceptionThrown {
85+
match self {
86+
Error::Value(exc) => exc.throw(scope),
87+
Error::Exception(thrown) => thrown,
88+
Error::String(s) => TypeError(s).throw(scope),
89+
}
90+
}
91+
}
92+
93+
impl<'s> From<ExceptionThrown> for Error<'s> {
94+
fn from(v: ExceptionThrown) -> Self {
95+
Self::Exception(v)
96+
}
97+
}
98+
99+
impl<'s> From<v8::Local<'s, v8::Value>> for Error<'s> {
100+
fn from(v: v8::Local<'s, v8::Value>) -> Self {
101+
Self::Value(v)
102+
}
103+
}
104+
105+
impl de::Error for Error<'_> {
106+
fn custom(msg: impl core::fmt::Display) -> Self {
107+
Self::String(msg.to_string())
108+
}
109+
}
110+
111+
fn extend_local<'s, T>(local: v8::Local<'s, T>) -> &'s T {
112+
unsafe { std::mem::transmute::<&T, &'s T>(&local) }
113+
}
114+
115+
macro_rules! deserialize_primitive {
116+
($dmethod:ident, $t:ty) => {
117+
fn $dmethod(self) -> Result<$t, Self::Error> {
118+
FromValue::from_value(self.common.scope, self.input).map_err(Error::Value)
119+
}
120+
};
121+
}
122+
123+
impl<'de, 'a, 's: 'de, 'x> de::Deserializer<'de> for Deserializer<'a, 's> {
124+
type Error = Error<'s>;
125+
126+
fn deserialize_product<V: de::ProductVisitor<'de>>(self, visitor: V) -> Result<V::Output, Self::Error> {
127+
let obj = cast!(
128+
self.input,
129+
v8::Object,
130+
"object for product type {}",
131+
visitor.product_name().unwrap_or("")
132+
)
133+
.map_err_exc(self.common.scope)?;
134+
135+
visitor.visit_named_product(ProductAccess {
136+
common: self.common,
137+
obj,
138+
next_value: None,
139+
n: 0,
140+
})
141+
}
142+
143+
fn deserialize_sum<V: de::SumVisitor<'de>>(self, visitor: V) -> Result<V::Output, Self::Error> {
144+
let scope = &mut *self.common.scope;
145+
let val = if visitor.is_option() {
146+
if self.input.is_null_or_undefined() {
147+
return visitor.visit_sum(de::NoneAccess::new());
148+
}
149+
let val = cast!(self.input, v8::Object, "nullish or {{some:_}} for option").map_err_exc(scope)?;
150+
let some_field = self.common.key_cache.some(scope);
151+
if val.has_own_property(scope, some_field.into()).err()? {
152+
let value = val.get(scope, some_field.into()).err()?;
153+
return visitor.visit_sum(SumAccess {
154+
common: self.common,
155+
tag: some_field,
156+
value,
157+
});
158+
}
159+
val
160+
} else {
161+
cast!(
162+
self.input,
163+
v8::Object,
164+
"object for sum type {}",
165+
visitor.sum_name().unwrap_or("")
166+
)
167+
.map_err_exc(scope)?
168+
};
169+
170+
let tag_field = self.common.key_cache.tag(scope);
171+
let tag = val.get(scope, tag_field.into()).err()?;
172+
let tag = cast!(
173+
tag,
174+
v8::String,
175+
"string for sum tag of {}",
176+
visitor.sum_name().unwrap_or("")
177+
)
178+
.map_err_exc(scope)?;
179+
180+
let value_field = self.common.key_cache.value(scope);
181+
let value = val.get(scope, value_field.into()).err()?;
182+
183+
visitor.visit_sum(SumAccess {
184+
common: self.common,
185+
tag,
186+
value,
187+
})
188+
}
189+
190+
deserialize_primitive!(deserialize_bool, bool);
191+
192+
deserialize_primitive!(deserialize_u8, u8);
193+
deserialize_primitive!(deserialize_u16, u16);
194+
deserialize_primitive!(deserialize_u32, u32);
195+
deserialize_primitive!(deserialize_u64, u64);
196+
deserialize_primitive!(deserialize_u128, u128);
197+
deserialize_primitive!(deserialize_u256, u256);
198+
199+
deserialize_primitive!(deserialize_i8, i8);
200+
deserialize_primitive!(deserialize_i16, i16);
201+
deserialize_primitive!(deserialize_i32, i32);
202+
deserialize_primitive!(deserialize_i64, i64);
203+
deserialize_primitive!(deserialize_i128, i128);
204+
deserialize_primitive!(deserialize_i256, i256);
205+
206+
deserialize_primitive!(deserialize_f64, f64);
207+
deserialize_primitive!(deserialize_f32, f32);
208+
209+
fn deserialize_str<V: de::SliceVisitor<'de, str>>(self, visitor: V) -> Result<V::Output, Self::Error> {
210+
let scope = self.common.scope;
211+
let val = cast!(self.input, v8::String, "string").map_err_exc(scope)?;
212+
let mut buf = scratch_buf::<64>();
213+
match val.to_rust_cow_lossy(scope, &mut buf) {
214+
Cow::Borrowed(s) => visitor.visit(s),
215+
Cow::Owned(string) => visitor.visit_owned(string),
216+
}
217+
}
218+
219+
fn deserialize_bytes<V: de::SliceVisitor<'de, [u8]>>(self, visitor: V) -> Result<V::Output, Self::Error> {
220+
let scope = self.common.scope;
221+
let arr = cast!(self.input, v8::Uint8Array, "Uint8Array for bytes").map_err_exc(scope)?;
222+
let storage: &'static mut [u8] = &mut [0; v8::TYPED_ARRAY_MAX_SIZE_IN_HEAP];
223+
let bytes = extend_local(arr).get_contents(storage);
224+
visitor.visit_borrowed(bytes)
225+
}
226+
227+
fn deserialize_array_seed<V: de::ArrayVisitor<'de, T::Output>, T: de::DeserializeSeed<'de> + Clone>(
228+
self,
229+
visitor: V,
230+
seed: T,
231+
) -> Result<V::Output, Self::Error> {
232+
let arr = cast!(self.input, v8::Array, "Array").map_err_exc(self.common.scope)?;
233+
visitor.visit(ArrayAccess::new(arr, self.common, seed))
234+
}
235+
}
236+
237+
struct ProductAccess<'a, 's> {
238+
common: DeserializerCommon<'a, 's>,
239+
obj: v8::Local<'s, v8::Object>,
240+
next_value: Option<v8::Local<'s, v8::Value>>,
241+
n: usize,
242+
}
243+
244+
impl<'de, 's: 'de> de::NamedProductAccess<'de> for ProductAccess<'_, 's> {
245+
type Error = Error<'s>;
246+
247+
fn get_field_ident<V: de::FieldNameVisitor<'de>>(&mut self, visitor: V) -> Result<Option<V::Output>, Self::Error> {
248+
let scope = &mut *self.common.scope;
249+
while let Some(field) = visitor.field_names().nth(self.n) {
250+
let i = self.n;
251+
self.n += 1;
252+
253+
let Some(field) = field else {
254+
continue;
255+
};
256+
257+
let key = v8_struct_key(scope, field);
258+
if !self.obj.has_own_property(scope, key.into()).err()? {
259+
continue;
260+
}
261+
let val = self.obj.get(scope, key.into()).err()?;
262+
self.next_value = Some(val);
263+
return visitor.visit_seq(i, field).map(Some);
264+
}
265+
Ok(None)
266+
}
267+
268+
fn get_field_value_seed<T: de::DeserializeSeed<'de>>(&mut self, seed: T) -> Result<T::Output, Self::Error> {
269+
let val = self
270+
.next_value
271+
.take()
272+
.expect("Call next_key_seed before next_value_seed");
273+
seed.deserialize(Deserializer {
274+
common: self.common.reborrow(),
275+
input: val,
276+
})
277+
}
278+
}
279+
280+
struct SumAccess<'a, 's> {
281+
common: DeserializerCommon<'a, 's>,
282+
tag: v8::Local<'s, v8::String>,
283+
value: v8::Local<'s, v8::Value>,
284+
// p1: std::marker::PhantomData<&'x ()>,
285+
}
286+
287+
impl<'de, 'a, 's: 'de> de::SumAccess<'de> for SumAccess<'a, 's> {
288+
type Error = Error<'s>;
289+
type Variant = Deserializer<'a, 's>;
290+
291+
fn variant<V: de::VariantVisitor>(self, visitor: V) -> Result<(V::Output, Self::Variant), Self::Error> {
292+
let mut buf = scratch_buf::<32>();
293+
let name = self.tag.to_rust_cow_lossy(self.common.scope, &mut buf);
294+
let variant = visitor.visit_name::<Self::Error>(&name)?;
295+
let dpayload = Deserializer {
296+
common: self.common,
297+
input: self.value,
298+
};
299+
300+
Ok((variant, dpayload))
301+
}
302+
}
303+
304+
impl<'de, 'a, 's: 'de> de::VariantAccess<'de> for Deserializer<'a, 's> {
305+
type Error = Error<'s>;
306+
307+
fn deserialize_seed<T: de::DeserializeSeed<'de>>(self, seed: T) -> Result<T::Output, Self::Error> {
308+
seed.deserialize(self)
309+
}
310+
}
311+
312+
struct ArrayAccess<'a, 's, T> {
313+
common: DeserializerCommon<'a, 's>,
314+
arr: v8::Local<'s, v8::Array>,
315+
seeds: std::iter::RepeatN<T>,
316+
len: u32,
317+
}
318+
319+
impl<'de, 'a, 's, T> ArrayAccess<'a, 's, T>
320+
where
321+
T: de::DeserializeSeed<'de> + Clone,
322+
{
323+
fn new(arr: v8::Local<'s, v8::Array>, common: DeserializerCommon<'a, 's>, seed: T) -> Self {
324+
let len = arr.length();
325+
Self {
326+
arr,
327+
common,
328+
seeds: std::iter::repeat_n(seed, len as usize),
329+
len,
330+
}
331+
}
332+
}
333+
334+
impl<'de, 's: 'de, T> de::ArrayAccess<'de> for ArrayAccess<'_, 's, T>
335+
where
336+
T: de::DeserializeSeed<'de> + Clone,
337+
{
338+
type Element = T::Output;
339+
type Error = Error<'s>;
340+
341+
fn next_element(&mut self) -> Result<Option<Self::Element>, Self::Error> {
342+
let i = self.len - self.seeds.len() as u32;
343+
if let Some(seed) = self.seeds.next() {
344+
let val = self.arr.get_index(self.common.scope, i).err()?;
345+
let val = seed.deserialize(Deserializer {
346+
common: self.common.reborrow(),
347+
input: val,
348+
})?;
349+
Ok(Some(val))
350+
} else {
351+
Ok(None)
352+
}
353+
}
354+
355+
fn size_hint(&self) -> Option<usize> {
356+
Some(self.seeds.len())
357+
}
358+
}

0 commit comments

Comments
 (0)