Skip to content

Commit 815c10d

Browse files
authored
Package component model options in an index (#11324)
* Package component model options in an index This commit is a refactoring of how canonical ABI options are handled during compilation and runtime. Previously options were "exploded" meaning that options were all passed around as parameters but this was a bummer for a few reasons: * This is `unsafe`-prone as options have raw pointers such as memory and functions. This meant that all functions/operations working with options were fundamentally `unsafe`. * This was unwieldy as the set of options continues to grow larger over time. The `VMLoweringCallee` function previously had 10+ parameters, most of which were canonical ABI options. To solve these two problems options are now intern'd at compile time to an `OptionsIndex`, a 32-bit value. This is stored as a new table in component metadata and consulted at runtime. This means that `OptionsIndex` can be passed around with an instance for a much safer means of threading options around. Additionally there's no need to pass around all parameters individually and instead just one parameter, `OptionsIndex`, need be threaded through. This commit additionally overhauls trampoline generation for the component compiler to avoid a function-per-intrinsic and instead have a single function that all intrinsics use. I found this easier to understand and helps codify that all intrinsics are basically the same with some minor details differing between them. The end result of this is (hopefully) a net simplification of the component compiler in addition to a large amount of removal of `unsafe` code in the async implementation as only safe types are passed around now instead of raw pointers. Closes #10143 Closes #11188 * Fill out some TODO comments
1 parent 0f457fa commit 815c10d

File tree

16 files changed

+1268
-1824
lines changed

16 files changed

+1268
-1824
lines changed

crates/cranelift/src/compiler/component.rs

Lines changed: 714 additions & 1006 deletions
Large diffs are not rendered by default.

crates/environ/src/component.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,15 @@ macro_rules! foreach_builtin_component_function {
100100
#[cfg(feature = "component-model-async")]
101101
backpressure_set(vmctx: vmctx, caller_instance: u32, enabled: u32) -> bool;
102102
#[cfg(feature = "component-model-async")]
103-
task_return(vmctx: vmctx, ty: u32, memory: ptr_u8, string_encoding: u8, storage: ptr_u8, storage_len: size) -> bool;
103+
task_return(vmctx: vmctx, ty: u32, options: u32, storage: ptr_u8, storage_len: size) -> bool;
104104
#[cfg(feature = "component-model-async")]
105105
task_cancel(vmctx: vmctx, caller_instance: u32) -> bool;
106106
#[cfg(feature = "component-model-async")]
107107
waitable_set_new(vmctx: vmctx, caller_instance: u32) -> u64;
108108
#[cfg(feature = "component-model-async")]
109-
waitable_set_wait(vmctx: vmctx, caller_instance: u32, async_: u8, memory: ptr_u8, set: u32, payload: u32) -> u64;
109+
waitable_set_wait(vmctx: vmctx, options: u32, set: u32, payload: u32) -> u64;
110110
#[cfg(feature = "component-model-async")]
111-
waitable_set_poll(vmctx: vmctx, caller_instance: u32, async_: u8, memory: ptr_u8, set: u32, payload: u32) -> u64;
111+
waitable_set_poll(vmctx: vmctx, options: u32, set: u32, payload: u32) -> u64;
112112
#[cfg(feature = "component-model-async")]
113113
waitable_set_drop(vmctx: vmctx, caller_instance: u32, set: u32) -> bool;
114114
#[cfg(feature = "component-model-async")]
@@ -134,15 +134,15 @@ macro_rules! foreach_builtin_component_function {
134134
storage_len: size
135135
) -> bool;
136136
#[cfg(feature = "component-model-async")]
137-
sync_start(vmctx: vmctx, callback: ptr_u8, callee: ptr_u8, param_count: u32, storage: ptr_u8, storage_len: size) -> bool;
137+
sync_start(vmctx: vmctx, callback: ptr_u8, storage: ptr_u8, storage_len: size, callee: ptr_u8, param_count: u32) -> bool;
138138
#[cfg(feature = "component-model-async")]
139139
async_start(vmctx: vmctx, callback: ptr_u8, post_return: ptr_u8, callee: ptr_u8, param_count: u32, result_count: u32, flags: u32) -> u64;
140140
#[cfg(feature = "component-model-async")]
141141
future_new(vmctx: vmctx, ty: u32) -> u64;
142142
#[cfg(feature = "component-model-async")]
143-
future_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, async_: u8, ty: u32, future: u32, address: u32) -> u64;
143+
future_write(vmctx: vmctx, ty: u32, options: u32, future: u32, address: u32) -> u64;
144144
#[cfg(feature = "component-model-async")]
145-
future_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, async_: u8, ty: u32, future: u32, address: u32) -> u64;
145+
future_read(vmctx: vmctx, ty: u32, options: u32, future: u32, address: u32) -> u64;
146146
#[cfg(feature = "component-model-async")]
147147
future_cancel_write(vmctx: vmctx, ty: u32, async_: u8, writer: u32) -> u64;
148148
#[cfg(feature = "component-model-async")]
@@ -154,9 +154,9 @@ macro_rules! foreach_builtin_component_function {
154154
#[cfg(feature = "component-model-async")]
155155
stream_new(vmctx: vmctx, ty: u32) -> u64;
156156
#[cfg(feature = "component-model-async")]
157-
stream_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, async_: u8, ty: u32, stream: u32, address: u32, count: u32) -> u64;
157+
stream_write(vmctx: vmctx, ty: u32, options: u32, stream: u32, address: u32, count: u32) -> u64;
158158
#[cfg(feature = "component-model-async")]
159-
stream_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, async_: u8, ty: u32, stream: u32, address: u32, count: u32) -> u64;
159+
stream_read(vmctx: vmctx, ty: u32, options: u32, stream: u32, address: u32, count: u32) -> u64;
160160
#[cfg(feature = "component-model-async")]
161161
stream_cancel_write(vmctx: vmctx, ty: u32, async_: u8, writer: u32) -> u64;
162162
#[cfg(feature = "component-model-async")]
@@ -166,13 +166,13 @@ macro_rules! foreach_builtin_component_function {
166166
#[cfg(feature = "component-model-async")]
167167
stream_drop_readable(vmctx: vmctx, ty: u32, reader: u32) -> bool;
168168
#[cfg(feature = "component-model-async")]
169-
flat_stream_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, async_: u8, ty: u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
169+
flat_stream_write(vmctx: vmctx, ty: u32, options:u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
170170
#[cfg(feature = "component-model-async")]
171-
flat_stream_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, async_: u8, ty: u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
171+
flat_stream_read(vmctx: vmctx, ty: u32, options: u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
172172
#[cfg(feature = "component-model-async")]
173-
error_context_new(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, debug_msg_address: u32, debug_msg_len: u32) -> u64;
173+
error_context_new(vmctx: vmctx, ty: u32, options: u32, debug_msg_address: u32, debug_msg_len: u32) -> u64;
174174
#[cfg(feature = "component-model-async")]
175-
error_context_debug_message(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, err_ctx_handle: u32, debug_msg_address: u32) -> bool;
175+
error_context_debug_message(vmctx: vmctx, ty: u32, options: u32, err_ctx_handle: u32, debug_msg_address: u32) -> bool;
176176
#[cfg(feature = "component-model-async")]
177177
error_context_drop(vmctx: vmctx, ty: u32, err_ctx_handle: u32) -> bool;
178178
#[cfg(feature = "component-model-async")]
@@ -186,7 +186,7 @@ macro_rules! foreach_builtin_component_function {
186186
#[cfg(feature = "component-model-async")]
187187
context_set(vmctx: vmctx, slot: u32, val: u32) -> bool;
188188

189-
trap(vmctx: vmctx, code: u8);
189+
trap(vmctx: vmctx, code: u8) -> bool;
190190

191191
utf8_to_utf8(vmctx: vmctx, src: ptr_u8, len: size, dst: ptr_u8) -> bool;
192192
utf16_to_utf16(vmctx: vmctx, src: ptr_u16, len: size, dst: ptr_u16) -> bool;

crates/environ/src/component/dfg.rs

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ pub struct ComponentDfg {
138138
/// of this component by idnicating what order operations should be
139139
/// performed during instantiation.
140140
pub side_effects: Vec<SideEffect>,
141+
142+
/// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by
143+
/// this component.
144+
pub options: Intern<OptionsId, CanonicalOptions>,
141145
}
142146

143147
/// Possible side effects that are possible with instantiating this component.
@@ -211,6 +215,7 @@ id! {
211215
pub struct AdapterId(u32);
212216
pub struct PostReturnId(u32);
213217
pub struct AdapterModuleId(u32);
218+
pub struct OptionsId(u32);
214219
}
215220

216221
/// Same as `info::InstantiateModule`
@@ -229,7 +234,7 @@ pub enum Export {
229234
LiftedFunction {
230235
ty: TypeFuncIndex,
231236
func: CoreDef,
232-
options: CanonicalOptions,
237+
options: OptionsId,
233238
},
234239
ModuleStatic {
235240
ty: ComponentCoreModuleTypeId,
@@ -300,7 +305,7 @@ impl<T> CoreExport<T> {
300305
pub enum Trampoline {
301306
LowerImport {
302307
import: RuntimeImportIndex,
303-
options: CanonicalOptions,
308+
options: OptionsId,
304309
lower_ty: TypeFuncIndex,
305310
},
306311
Transcoder {
@@ -319,7 +324,7 @@ pub enum Trampoline {
319324
},
320325
TaskReturn {
321326
results: TypeTupleIndex,
322-
options: CanonicalOptions,
327+
options: OptionsId,
323328
},
324329
TaskCancel {
325330
instance: RuntimeComponentInstanceIndex,
@@ -328,14 +333,10 @@ pub enum Trampoline {
328333
instance: RuntimeComponentInstanceIndex,
329334
},
330335
WaitableSetWait {
331-
instance: RuntimeComponentInstanceIndex,
332-
async_: bool,
333-
memory: MemoryId,
336+
options: OptionsId,
334337
},
335338
WaitableSetPoll {
336-
instance: RuntimeComponentInstanceIndex,
337-
async_: bool,
338-
memory: MemoryId,
339+
options: OptionsId,
339340
},
340341
WaitableSetDrop {
341342
instance: RuntimeComponentInstanceIndex,
@@ -358,11 +359,11 @@ pub enum Trampoline {
358359
},
359360
StreamRead {
360361
ty: TypeStreamTableIndex,
361-
options: CanonicalOptions,
362+
options: OptionsId,
362363
},
363364
StreamWrite {
364365
ty: TypeStreamTableIndex,
365-
options: CanonicalOptions,
366+
options: OptionsId,
366367
},
367368
StreamCancelRead {
368369
ty: TypeStreamTableIndex,
@@ -383,11 +384,11 @@ pub enum Trampoline {
383384
},
384385
FutureRead {
385386
ty: TypeFutureTableIndex,
386-
options: CanonicalOptions,
387+
options: OptionsId,
387388
},
388389
FutureWrite {
389390
ty: TypeFutureTableIndex,
390-
options: CanonicalOptions,
391+
options: OptionsId,
391392
},
392393
FutureCancelRead {
393394
ty: TypeFutureTableIndex,
@@ -405,11 +406,11 @@ pub enum Trampoline {
405406
},
406407
ErrorContextNew {
407408
ty: TypeComponentLocalErrorContextTableIndex,
408-
options: CanonicalOptions,
409+
options: OptionsId,
409410
},
410411
ErrorContextDebugMessage {
411412
ty: TypeComponentLocalErrorContextTableIndex,
412-
options: CanonicalOptions,
413+
options: OptionsId,
413414
},
414415
ErrorContextDrop {
415416
ty: TypeComponentLocalErrorContextTableIndex,
@@ -554,6 +555,8 @@ impl ComponentDfg {
554555
trampolines: Default::default(),
555556
trampoline_defs: Default::default(),
556557
trampoline_map: Default::default(),
558+
options: Default::default(),
559+
options_map: Default::default(),
557560
};
558561

559562
// Handle all side effects of this component in the order that they're
@@ -585,6 +588,7 @@ impl ComponentDfg {
585588
initializers: linearize.initializers,
586589
trampolines: linearize.trampolines,
587590
num_lowerings: linearize.num_lowerings,
591+
options: linearize.options,
588592

589593
num_runtime_memories: linearize.runtime_memories.len() as u32,
590594
num_runtime_tables: linearize.runtime_tables.len() as u32,
@@ -621,13 +625,15 @@ struct LinearizeDfg<'a> {
621625
initializers: Vec<GlobalInitializer>,
622626
trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
623627
trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
628+
options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
624629
trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
625630
runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
626631
runtime_tables: HashMap<TableId, RuntimeTableIndex>,
627632
runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
628633
runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
629634
runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
630635
runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
636+
options_map: HashMap<OptionsId, OptionsIndex>,
631637
num_lowerings: u32,
632638
}
633639

@@ -699,7 +705,7 @@ impl LinearizeDfg<'_> {
699705
let item = match export {
700706
Export::LiftedFunction { ty, func, options } => {
701707
let func = self.core_def(func);
702-
let options = self.options(options);
708+
let options = self.options(*options);
703709
info::Export::LiftedFunction {
704710
ty: *ty,
705711
func,
@@ -731,7 +737,16 @@ impl LinearizeDfg<'_> {
731737
Ok(items.push(item))
732738
}
733739

734-
fn options(&mut self, options: &CanonicalOptions) -> info::CanonicalOptions {
740+
fn options(&mut self, options: OptionsId) -> OptionsIndex {
741+
self.intern_no_init(
742+
options,
743+
|me| &mut me.options_map,
744+
|me, options| me.convert_options(options),
745+
)
746+
}
747+
748+
fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
749+
let options = &self.dfg.options[options];
735750
let data_model = match options.data_model {
736751
CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
737752
CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
@@ -743,15 +758,16 @@ impl LinearizeDfg<'_> {
743758
};
744759
let callback = options.callback.map(|mem| self.runtime_callback(mem));
745760
let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
746-
info::CanonicalOptions {
761+
let options = info::CanonicalOptions {
747762
instance: options.instance,
748763
string_encoding: options.string_encoding,
749764
callback,
750765
post_return,
751766
async_: options.async_,
752767
core_type: options.core_type,
753768
data_model,
754-
}
769+
};
770+
self.options.push(options)
755771
}
756772

757773
fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
@@ -818,7 +834,7 @@ impl LinearizeDfg<'_> {
818834
});
819835
info::Trampoline::LowerImport {
820836
index,
821-
options: self.options(options),
837+
options: self.options(*options),
822838
lower_ty: *lower_ty,
823839
}
824840
}
@@ -844,31 +860,19 @@ impl LinearizeDfg<'_> {
844860
},
845861
Trampoline::TaskReturn { results, options } => info::Trampoline::TaskReturn {
846862
results: *results,
847-
options: self.options(options),
863+
options: self.options(*options),
848864
},
849865
Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
850866
instance: *instance,
851867
},
852868
Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
853869
instance: *instance,
854870
},
855-
Trampoline::WaitableSetWait {
856-
instance,
857-
async_,
858-
memory,
859-
} => info::Trampoline::WaitableSetWait {
860-
instance: *instance,
861-
async_: *async_,
862-
memory: self.runtime_memory(*memory),
871+
Trampoline::WaitableSetWait { options } => info::Trampoline::WaitableSetWait {
872+
options: self.options(*options),
863873
},
864-
Trampoline::WaitableSetPoll {
865-
instance,
866-
async_,
867-
memory,
868-
} => info::Trampoline::WaitableSetPoll {
869-
instance: *instance,
870-
async_: *async_,
871-
memory: self.runtime_memory(*memory),
874+
Trampoline::WaitableSetPoll { options } => info::Trampoline::WaitableSetPoll {
875+
options: self.options(*options),
872876
},
873877
Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
874878
instance: *instance,
@@ -887,11 +891,11 @@ impl LinearizeDfg<'_> {
887891
Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },
888892
Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {
889893
ty: *ty,
890-
options: self.options(options),
894+
options: self.options(*options),
891895
},
892896
Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {
893897
ty: *ty,
894-
options: self.options(options),
898+
options: self.options(*options),
895899
},
896900
Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead {
897901
ty: *ty,
@@ -910,11 +914,11 @@ impl LinearizeDfg<'_> {
910914
Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },
911915
Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {
912916
ty: *ty,
913-
options: self.options(options),
917+
options: self.options(*options),
914918
},
915919
Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {
916920
ty: *ty,
917-
options: self.options(options),
921+
options: self.options(*options),
918922
},
919923
Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead {
920924
ty: *ty,
@@ -932,12 +936,12 @@ impl LinearizeDfg<'_> {
932936
}
933937
Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {
934938
ty: *ty,
935-
options: self.options(options),
939+
options: self.options(*options),
936940
},
937941
Trampoline::ErrorContextDebugMessage { ty, options } => {
938942
info::Trampoline::ErrorContextDebugMessage {
939943
ty: *ty,
940-
options: self.options(options),
944+
options: self.options(*options),
941945
}
942946
}
943947
Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty },
@@ -1034,6 +1038,35 @@ impl LinearizeDfg<'_> {
10341038
generate: impl FnOnce(&mut Self, K) -> T,
10351039
init: impl FnOnce(V, T) -> GlobalInitializer,
10361040
) -> V
1041+
where
1042+
K: Hash + Eq + Copy,
1043+
V: EntityRef,
1044+
{
1045+
self.intern_(key, map, generate, |me, key, val| {
1046+
me.initializers.push(init(key, val));
1047+
})
1048+
}
1049+
1050+
fn intern_no_init<K, V, T>(
1051+
&mut self,
1052+
key: K,
1053+
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1054+
generate: impl FnOnce(&mut Self, K) -> T,
1055+
) -> V
1056+
where
1057+
K: Hash + Eq + Copy,
1058+
V: EntityRef,
1059+
{
1060+
self.intern_(key, map, generate, |_me, _key, _val| {})
1061+
}
1062+
1063+
fn intern_<K, V, T>(
1064+
&mut self,
1065+
key: K,
1066+
map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1067+
generate: impl FnOnce(&mut Self, K) -> T,
1068+
init: impl FnOnce(&mut Self, V, T),
1069+
) -> V
10371070
where
10381071
K: Hash + Eq + Copy,
10391072
V: EntityRef,
@@ -1043,7 +1076,7 @@ impl LinearizeDfg<'_> {
10431076
}
10441077
let tmp = generate(self, key);
10451078
let index = V::new(map(self).len());
1046-
self.initializers.push(init(index, tmp));
1079+
init(self, index, tmp);
10471080
let prev = map(self).insert(key, index);
10481081
assert!(prev.is_none());
10491082
index

0 commit comments

Comments
 (0)