1
1
use std:: any:: { Any , TypeId } ;
2
+ use std:: mem:: MaybeUninit ;
2
3
use std:: ops:: Deref ;
3
- use std:: { marker, mem} ;
4
+ use std:: ptr:: DynMetadata ;
5
+ use std:: { marker, mem, ptr} ;
4
6
5
7
use js_sys:: { Array , Function , Reflect , Uint8Array } ;
6
8
use wasm_bindgen:: closure:: Closure ;
@@ -11,7 +13,6 @@ use web_sys::HtmlElement;
11
13
use crate :: dom:: { impl_shadow_host_for_element, DynamicElement , Name , ParentNode } ;
12
14
use crate :: finalization_registry:: FinalizationRegistry ;
13
15
use crate :: html:: { impl_html_element_traits, CustomElementName } ;
14
- use crate :: util:: type_id_to_u64;
15
16
use crate :: InvalidCast ;
16
17
use crate :: { dom_exception_wrapper, impl_common_wrapper_traits} ;
17
18
@@ -20,24 +21,19 @@ thread_local! {
20
21
let callback = |held_value: JsValue | {
21
22
// Reconstruct the Box<dyn Any> that holds the data, then drop it.
22
23
23
- let pointer_data : Uint8Array = held_value. unchecked_into( ) ;
24
+ let serialized_data : Uint8Array = held_value. unchecked_into( ) ;
24
25
25
- // Copy pointer data to WASM linear memory that we can operate on.
26
- let mut scratch = [ 0u8 ; 24 ] ;
27
- let size_of_usize = mem:: size_of:: <usize >( ) ;
26
+ let mut uninit_custom_element_data = MaybeUninit :: <CustomElementData >:: uninit( ) ;
27
+ let data_ptr = uninit_custom_element_data. as_mut_ptr( ) ;
28
28
29
- pointer_data . copy_to ( & mut scratch [ ..size_of_usize * 2 + 8 ] ) ;
29
+ deserialize_custom_element_data ( & wasm_bindgen :: memory ( ) , data_ptr , & serialized_data ) ;
30
30
31
- let ( address_bytes, rest) = scratch. split_at( size_of_usize) ;
32
- let ( vtable_bytes, _) = rest. split_at( size_of_usize) ;
33
-
34
- let address_usize = usize :: from_ne_bytes( address_bytes. try_into( ) . unwrap_throw( ) ) ;
35
- let vtable_usize = usize :: from_ne_bytes( vtable_bytes. try_into( ) . unwrap_throw( ) ) ;
36
-
37
- let ptr: * mut dyn Any = unsafe { mem:: transmute( ( address_usize, vtable_usize) ) } ;
31
+ let custom_element_data = unsafe {
32
+ uninit_custom_element_data. assume_init( )
33
+ } ;
38
34
39
35
unsafe {
40
- mem:: drop( Box :: from_raw( ptr ) ) ;
36
+ mem:: drop( Box :: from_raw( custom_element_data . to_dyn_any_ptr ( ) ) ) ;
41
37
}
42
38
} ;
43
39
@@ -51,6 +47,18 @@ thread_local! {
51
47
} ;
52
48
}
53
49
50
+ struct CustomElementData {
51
+ address : * mut ( ) ,
52
+ metadata : DynMetadata < dyn Any > ,
53
+ type_id : TypeId ,
54
+ }
55
+
56
+ impl CustomElementData {
57
+ fn to_dyn_any_ptr ( & self ) -> * mut dyn Any {
58
+ ptr:: from_raw_parts_mut ( self . address , self . metadata )
59
+ }
60
+ }
61
+
54
62
pub ( crate ) mod extendable_element_seal {
55
63
pub trait Seal {
56
64
const EXTENDED_NAME : Option < & ' static str > ;
@@ -95,14 +103,14 @@ where
95
103
E : ExtendableElement ,
96
104
{
97
105
fn from_raw_unchecked ( raw : RawCustomElement ) -> Self {
98
- let mut scratch = [ 0u8 ; 24 ] ;
99
- let size_of_usize = mem:: size_of :: < usize > ( ) ;
106
+ let mut uninit_custom_element_data = MaybeUninit :: < CustomElementData > :: uninit ( ) ;
107
+ let data_ptr = uninit_custom_element_data. as_mut_ptr ( ) ;
108
+
109
+ raw. deserialize_custom_element_data ( & wasm_bindgen:: memory ( ) , data_ptr) ;
100
110
101
- raw . data ( ) . copy_to ( & mut scratch [ 0 ..size_of_usize * 2 + 8 ] ) ;
111
+ let custom_element_data = unsafe { uninit_custom_element_data . assume_init ( ) } ;
102
112
103
- let data_ptr_bits =
104
- usize:: from_ne_bytes ( scratch[ ..size_of_usize] . try_into ( ) . unwrap_throw ( ) ) ;
105
- let data = <* const T >:: from_bits ( data_ptr_bits) ;
113
+ let data = custom_element_data. address as * const T ;
106
114
let extended = E :: from_web_sys_html_element_unchecked ( raw. into ( ) ) ;
107
115
108
116
CustomElement { data, extended }
@@ -139,36 +147,36 @@ where
139
147
fn try_from ( element : DynamicElement ) -> Result < Self , Self :: Error > {
140
148
let element: web_sys:: Element = element. into ( ) ;
141
149
142
- if let Ok ( value) = Reflect :: get ( element. as_ref ( ) , & "__arwa_custom_element_data" . into ( ) ) {
143
- if !value. is_undefined ( ) {
144
- let data: Uint8Array = value. unchecked_into ( ) ;
145
- let target_type_num = type_id_to_u64 ( TypeId :: of :: < CustomElement < T , E > > ( ) ) ;
150
+ let is_custom_element = Reflect :: has (
151
+ element. as_ref ( ) ,
152
+ & "__deserialize_custom_element_data" . into ( ) ,
153
+ )
154
+ . unwrap_or ( false ) ;
146
155
147
- let mut scratch = [ 0u8 ; 24 ] ;
148
- let size_of_usize = mem:: size_of :: < usize > ( ) ;
149
- let type_num_start = size_of_usize * 2 ;
150
- let type_num_end = size_of_usize * 2 + 8 ;
156
+ if is_custom_element {
157
+ let raw = element. unchecked_into :: < RawCustomElement > ( ) ;
151
158
152
- data. copy_to ( & mut scratch[ 0 ..size_of_usize * 2 + 8 ] ) ;
159
+ let mut uninit_custom_element_data = MaybeUninit :: < CustomElementData > :: uninit ( ) ;
160
+ let data_ptr = uninit_custom_element_data. as_mut_ptr ( ) ;
153
161
154
- let type_num = u64:: from_ne_bytes (
155
- scratch[ type_num_start..type_num_end]
156
- . try_into ( )
157
- . unwrap_throw ( ) ,
158
- ) ;
162
+ raw. deserialize_custom_element_data ( & wasm_bindgen:: memory ( ) , data_ptr) ;
159
163
160
- if type_num == target_type_num {
161
- let data_ptr_bits =
162
- usize:: from_ne_bytes ( scratch[ ..size_of_usize] . try_into ( ) . unwrap_throw ( ) ) ;
163
- let data = <* const T >:: from_bits ( data_ptr_bits) ;
164
- let extended = E :: from_web_sys_html_element_unchecked ( element. unchecked_into ( ) ) ;
164
+ let custom_element_data = unsafe { uninit_custom_element_data. assume_init ( ) } ;
165
+ let target_type_id = TypeId :: of :: < CustomElement < T , E > > ( ) ;
165
166
166
- return Ok ( CustomElement { data, extended } ) ;
167
- }
167
+ if custom_element_data. type_id == target_type_id {
168
+ let data = custom_element_data. address as * const T ;
169
+ let extended = E :: from_web_sys_html_element_unchecked ( raw. unchecked_into ( ) ) ;
170
+
171
+ Ok ( CustomElement { data, extended } )
172
+ } else {
173
+ Err ( InvalidCast :: new ( DynamicElement :: from (
174
+ raw. unchecked_into :: < web_sys:: Element > ( ) ,
175
+ ) ) )
168
176
}
177
+ } else {
178
+ Err ( InvalidCast :: new ( DynamicElement :: from ( element) ) )
169
179
}
170
-
171
- Err ( InvalidCast :: new ( DynamicElement :: from ( element) ) )
172
180
}
173
181
}
174
182
@@ -256,7 +264,6 @@ impl CustomElementRegistry {
256
264
} = descriptor;
257
265
258
266
let type_id = TypeId :: of :: < CustomElement < T , E > > ( ) ;
259
- let type_num = type_id_to_u64 ( type_id) ;
260
267
261
268
let constructor = move |extended : web_sys:: HtmlElement | {
262
269
let extended = E :: from_web_sys_html_element_unchecked ( extended) ;
@@ -265,25 +272,31 @@ impl CustomElementRegistry {
265
272
266
273
let data = Box :: new ( data) as Box < dyn Any > ;
267
274
let data_ptr = Box :: into_raw ( data) ;
268
- let ( address_ptr, vtable_ptr) : ( usize , usize ) = unsafe { mem:: transmute ( data_ptr) } ;
269
-
270
- let mut scratch = [ 0u8 ; 24 ] ;
271
- let size_of_usize = mem:: size_of :: < usize > ( ) ;
272
- let type_num_start = size_of_usize * 2 ;
273
- let type_num_end = size_of_usize * 2 + 8 ;
274
-
275
- scratch[ 0 ..size_of_usize] . copy_from_slice ( & address_ptr. to_ne_bytes ( ) ) ;
276
- scratch[ size_of_usize..type_num_start] . copy_from_slice ( & vtable_ptr. to_ne_bytes ( ) ) ;
277
- scratch[ type_num_start..type_num_end] . copy_from_slice ( & type_num. to_ne_bytes ( ) ) ;
275
+ let ( address, metadata) = data_ptr. to_raw_parts ( ) ;
276
+ let mut custom_element_data = CustomElementData {
277
+ address,
278
+ metadata,
279
+ type_id,
280
+ } ;
281
+ let ptr = & mut custom_element_data as * mut CustomElementData ;
278
282
279
- let data = Uint8Array :: new_with_length ( type_num_end as u32 ) ;
283
+ let serialized = serialize_custom_element_data (
284
+ & wasm_bindgen:: memory ( ) ,
285
+ ptr,
286
+ mem:: size_of :: < CustomElementData > ( ) as u32 ,
287
+ ) ;
280
288
281
- data. copy_from ( & scratch[ ..type_num_end] ) ;
289
+ // Make sure it doesn't drop early
290
+ mem:: drop ( custom_element_data) ;
282
291
283
- CUSTOM_ELEMENT_FINALIZATION_REGISTRY
284
- . with ( |r| r. register ( extended. as_web_sys_html_element ( ) . as_ref ( ) , data. as_ref ( ) ) ) ;
292
+ CUSTOM_ELEMENT_FINALIZATION_REGISTRY . with ( |r| {
293
+ r. register (
294
+ extended. as_web_sys_html_element ( ) . as_ref ( ) ,
295
+ serialized. as_ref ( ) ,
296
+ )
297
+ } ) ;
285
298
286
- data
299
+ serialized
287
300
} ;
288
301
289
302
let constructor_boxed =
@@ -389,10 +402,14 @@ dom_exception_wrapper!(RegisterCustomElementError);
389
402
#[ wasm_bindgen]
390
403
extern "C" {
391
404
#[ wasm_bindgen( extends = HtmlElement ) ]
392
- pub type RawCustomElement ;
393
-
394
- #[ wasm_bindgen( method, getter, js_name = "__arwa_custom_element_data" ) ]
395
- pub fn data ( this : & RawCustomElement ) -> Uint8Array ;
405
+ type RawCustomElement ;
406
+
407
+ #[ wasm_bindgen( method, js_name = "__deserialize_custom_element_data" ) ]
408
+ fn deserialize_custom_element_data (
409
+ this : & RawCustomElement ,
410
+ wasm_memory : & JsValue ,
411
+ ptr : * mut CustomElementData ,
412
+ ) ;
396
413
}
397
414
398
415
#[ wasm_bindgen( module = "/src/html/define_custom_element.js" ) ]
@@ -408,6 +425,20 @@ extern "C" {
408
425
attribute_changed_callback : & Function ,
409
426
observed_attributes : & Array ,
410
427
) -> Result < JsValue , JsValue > ;
428
+
429
+ #[ wasm_bindgen]
430
+ fn serialize_custom_element_data (
431
+ wasm_memory : & JsValue ,
432
+ pointer : * mut CustomElementData ,
433
+ size : u32 ,
434
+ ) -> Uint8Array ;
435
+
436
+ #[ wasm_bindgen]
437
+ fn deserialize_custom_element_data (
438
+ wasm_memory : & JsValue ,
439
+ pointer : * mut CustomElementData ,
440
+ serialized_data : & Uint8Array ,
441
+ ) ;
411
442
}
412
443
413
444
macro_rules! impl_extendable_element {
0 commit comments