Skip to content

Commit a6f4185

Browse files
authored
A couple minor refactorings to wasmtime-cranelift and FuncEnvironment (#10541)
* Stop returning a `WasmResult` from the bounds-checking code; it is actually infallible and we were just plumbing around results for no reason. * Split out a few small helper methods from `FuncEnvironment::make_heap`. This allows for reusing them in #10503
1 parent 8001451 commit a6f4185

File tree

3 files changed

+112
-71
lines changed

3 files changed

+112
-71
lines changed

crates/cranelift/src/bounds_checks.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use cranelift_codegen::{
2828
ir::{Expr, Fact},
2929
};
3030
use cranelift_frontend::FunctionBuilder;
31-
use wasmtime_environ::{Unsigned, WasmResult};
31+
use wasmtime_environ::Unsigned;
3232
use Reachability::*;
3333

3434
/// Helper used to emit bounds checks (as necessary) and compute the native
@@ -46,7 +46,7 @@ pub fn bounds_check_and_compute_addr(
4646
offset: u32,
4747
// Static size of the heap access.
4848
access_size: u8,
49-
) -> WasmResult<Reachability<ir::Value>> {
49+
) -> Reachability<ir::Value> {
5050
let pointer_bit_width = u16::try_from(env.pointer_type().bits()).unwrap();
5151
let bound_gv = heap.bound;
5252
let orig_index = index;
@@ -165,19 +165,19 @@ pub fn bounds_check_and_compute_addr(
165165
// Special case: trap immediately if `offset + access_size >
166166
// max_memory_size`, since we will end up being out-of-bounds regardless
167167
// of the given `index`.
168-
env.before_unconditionally_trapping_memory_access(builder)?;
168+
env.before_unconditionally_trapping_memory_access(builder);
169169
env.trap(builder, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
170-
return Ok(Unreachable);
170+
return Unreachable;
171171
}
172172

173173
// Special case: if this is a 32-bit platform and the `offset_and_size`
174174
// overflows the 32-bit address space then there's no hope of this ever
175175
// being in-bounds. We can't represent `offset_and_size` in CLIF as the
176176
// native pointer type anyway, so this is an unconditional trap.
177177
if pointer_bit_width < 64 && offset_and_size >= (1 << pointer_bit_width) {
178-
env.before_unconditionally_trapping_memory_access(builder)?;
178+
env.before_unconditionally_trapping_memory_access(builder);
179179
env.trap(builder, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
180-
return Ok(Unreachable);
180+
return Unreachable;
181181
}
182182

183183
// Special case for when we can completely omit explicit
@@ -226,27 +226,27 @@ pub fn bounds_check_and_compute_addr(
226226
can_use_virtual_memory,
227227
"static memories require the ability to use virtual memory"
228228
);
229-
return Ok(Reachable(compute_addr(
229+
return Reachable(compute_addr(
230230
&mut builder.cursor(),
231231
heap,
232232
env.pointer_type(),
233233
index,
234234
offset,
235235
AddrPcc::static32(heap.pcc_memory_type, memory_reservation + memory_guard_size),
236-
)));
236+
));
237237
}
238238

239239
// Special case when the `index` is a constant and statically known to be
240240
// in-bounds on this memory, no bounds checks necessary.
241241
if statically_in_bounds {
242-
return Ok(Reachable(compute_addr(
242+
return Reachable(compute_addr(
243243
&mut builder.cursor(),
244244
heap,
245245
env.pointer_type(),
246246
index,
247247
offset,
248248
AddrPcc::static32(heap.pcc_memory_type, memory_reservation + memory_guard_size),
249-
)));
249+
));
250250
}
251251

252252
// Special case for when we can rely on virtual memory, the minimum
@@ -287,7 +287,7 @@ pub fn bounds_check_and_compute_addr(
287287
adjusted_bound_value,
288288
Some(0),
289289
);
290-
return Ok(Reachable(explicit_check_oob_condition_and_compute_addr(
290+
return Reachable(explicit_check_oob_condition_and_compute_addr(
291291
env,
292292
builder,
293293
heap,
@@ -297,7 +297,7 @@ pub fn bounds_check_and_compute_addr(
297297
oob_behavior,
298298
AddrPcc::static32(heap.pcc_memory_type, memory_reservation),
299299
oob,
300-
)));
300+
));
301301
}
302302

303303
// Special case for when `offset + access_size == 1`:
@@ -320,7 +320,7 @@ pub fn bounds_check_and_compute_addr(
320320
bound,
321321
Some(0),
322322
);
323-
return Ok(Reachable(explicit_check_oob_condition_and_compute_addr(
323+
return Reachable(explicit_check_oob_condition_and_compute_addr(
324324
env,
325325
builder,
326326
heap,
@@ -330,7 +330,7 @@ pub fn bounds_check_and_compute_addr(
330330
oob_behavior,
331331
AddrPcc::dynamic(heap.pcc_memory_type, bound_gv),
332332
oob,
333-
)));
333+
));
334334
}
335335

336336
// Special case for when we know that there are enough guard
@@ -368,7 +368,7 @@ pub fn bounds_check_and_compute_addr(
368368
bound,
369369
Some(0),
370370
);
371-
return Ok(Reachable(explicit_check_oob_condition_and_compute_addr(
371+
return Reachable(explicit_check_oob_condition_and_compute_addr(
372372
env,
373373
builder,
374374
heap,
@@ -378,7 +378,7 @@ pub fn bounds_check_and_compute_addr(
378378
oob_behavior,
379379
AddrPcc::dynamic(heap.pcc_memory_type, bound_gv),
380380
oob,
381-
)));
381+
));
382382
}
383383

384384
// Special case for when `offset + access_size <= min_size`.
@@ -412,7 +412,7 @@ pub fn bounds_check_and_compute_addr(
412412
adjusted_bound,
413413
Some(adjustment),
414414
);
415-
return Ok(Reachable(explicit_check_oob_condition_and_compute_addr(
415+
return Reachable(explicit_check_oob_condition_and_compute_addr(
416416
env,
417417
builder,
418418
heap,
@@ -422,7 +422,7 @@ pub fn bounds_check_and_compute_addr(
422422
oob_behavior,
423423
AddrPcc::dynamic(heap.pcc_memory_type, bound_gv),
424424
oob,
425-
)));
425+
));
426426
}
427427

428428
// General case for dynamic bounds checks:
@@ -461,7 +461,7 @@ pub fn bounds_check_and_compute_addr(
461461
bound,
462462
Some(0),
463463
);
464-
Ok(Reachable(explicit_check_oob_condition_and_compute_addr(
464+
Reachable(explicit_check_oob_condition_and_compute_addr(
465465
env,
466466
builder,
467467
heap,
@@ -471,7 +471,7 @@ pub fn bounds_check_and_compute_addr(
471471
oob_behavior,
472472
AddrPcc::dynamic(heap.pcc_memory_type, bound_gv),
473473
oob,
474-
)))
474+
))
475475
}
476476

477477
/// Get the bound of a dynamic heap as an `ir::Value`.

crates/cranelift/src/func_environ.rs

Lines changed: 90 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,37 +1016,49 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
10161016
}
10171017
}
10181018

1019-
/// Add one level of indirection to a pointer-and-memtype pair:
1020-
/// generate a load in the code at the specified offset, and if
1021-
/// memtypes are in use, add a field to the original struct and
1022-
/// generate a new memtype for the pointee.
1023-
fn load_pointer_with_memtypes(
1019+
/// Create an `ir::Global` that does `load(ptr + offset)` and, when PCC and
1020+
/// memory types are enabled, adds a field to the pointer's memory type for
1021+
/// this value we are loading.
1022+
pub(crate) fn global_load_with_memory_type(
10241023
&mut self,
10251024
func: &mut ir::Function,
1025+
ptr: ir::GlobalValue,
10261026
offset: u32,
1027-
readonly: bool,
1028-
memtype: Option<ir::MemoryType>,
1027+
flags: ir::MemFlags,
1028+
ptr_mem_ty: Option<ir::MemoryType>,
10291029
) -> (ir::GlobalValue, Option<ir::MemoryType>) {
1030-
let vmctx = self.vmctx(func);
10311030
let pointee = func.create_global_value(ir::GlobalValueData::Load {
1032-
base: vmctx,
1031+
base: ptr,
10331032
offset: Offset32::new(i32::try_from(offset).unwrap()),
10341033
global_type: self.pointer_type(),
1035-
flags: MemFlags::trusted().with_readonly().with_can_move(),
1034+
flags,
10361035
});
10371036

1038-
let mt = memtype.map(|mt| {
1039-
let pointee_mt = self.create_empty_struct_memtype(func);
1040-
self.add_field_to_memtype(func, mt, offset, pointee_mt, readonly);
1037+
let pointee_mem_ty = ptr_mem_ty.map(|ptr_mem_ty| {
1038+
let pointee_mem_ty = self.create_empty_struct_memtype(func);
1039+
self.add_field_to_memtype(func, ptr_mem_ty, offset, pointee_mem_ty, flags.readonly());
10411040
func.global_value_facts[pointee] = Some(Fact::Mem {
1042-
ty: pointee_mt,
1041+
ty: pointee_mem_ty,
10431042
min_offset: 0,
10441043
max_offset: 0,
10451044
nullable: false,
10461045
});
1047-
pointee_mt
1046+
pointee_mem_ty
10481047
});
1049-
(pointee, mt)
1048+
1049+
(pointee, pointee_mem_ty)
1050+
}
1051+
1052+
/// Like `global_load_with_memory_type` but specialized for loads out of the
1053+
/// `vmctx`.
1054+
pub(crate) fn global_load_from_vmctx_with_memory_type(
1055+
&mut self,
1056+
func: &mut ir::Function,
1057+
offset: u32,
1058+
flags: ir::MemFlags,
1059+
) -> (ir::GlobalValue, Option<ir::MemoryType>) {
1060+
let vmctx = self.vmctx(func);
1061+
self.global_load_with_memory_type(func, vmctx, offset, flags, self.pcc_vmctx_memtype)
10501062
}
10511063

10521064
/// Helper to emit a conditional trap based on `trap_cond`.
@@ -2330,7 +2342,7 @@ impl FuncEnvironment<'_> {
23302342
let memory = self.module.memories[index];
23312343
let is_shared = memory.shared;
23322344

2333-
let (ptr, base_offset, current_length_offset, ptr_memtype) = {
2345+
let (base_ptr, base_offset, current_length_offset, ptr_memtype) = {
23342346
let vmctx = self.vmctx(func);
23352347
if let Some(def_index) = self.module.defined_memory_index(index) {
23362348
if is_shared {
@@ -2339,11 +2351,10 @@ impl FuncEnvironment<'_> {
23392351
// VMMemoryDefinition` to it and dereference that when
23402352
// atomically growing it.
23412353
let from_offset = self.offsets.vmctx_vmmemory_pointer(def_index);
2342-
let (memory, def_mt) = self.load_pointer_with_memtypes(
2354+
let (memory, def_mt) = self.global_load_from_vmctx_with_memory_type(
23432355
func,
23442356
from_offset,
2345-
true,
2346-
self.pcc_vmctx_memtype,
2357+
ir::MemFlags::trusted().with_readonly().with_can_move(),
23472358
);
23482359
let base_offset = i32::from(self.offsets.ptr.vmmemory_definition_base());
23492360
let current_length_offset =
@@ -2367,11 +2378,10 @@ impl FuncEnvironment<'_> {
23672378
}
23682379
} else {
23692380
let from_offset = self.offsets.vmctx_vmmemory_import_from(index);
2370-
let (memory, def_mt) = self.load_pointer_with_memtypes(
2381+
let (memory, def_mt) = self.global_load_from_vmctx_with_memory_type(
23712382
func,
23722383
from_offset,
2373-
true,
2374-
self.pcc_vmctx_memtype,
2384+
ir::MemFlags::trusted().with_readonly().with_can_move(),
23752385
);
23762386
let base_offset = i32::from(self.offsets.ptr.vmmemory_definition_base());
23772387
let current_length_offset =
@@ -2380,13 +2390,66 @@ impl FuncEnvironment<'_> {
23802390
}
23812391
};
23822392

2383-
let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
2384-
base: ptr,
2393+
let bound = func.create_global_value(ir::GlobalValueData::Load {
2394+
base: base_ptr,
23852395
offset: Offset32::new(current_length_offset),
23862396
global_type: pointer_type,
23872397
flags: MemFlags::trusted(),
23882398
});
23892399

2400+
let (base_fact, pcc_memory_type) = self.make_pcc_base_fact_and_type_for_memory(
2401+
func,
2402+
memory,
2403+
base_offset,
2404+
current_length_offset,
2405+
ptr_memtype,
2406+
bound,
2407+
);
2408+
2409+
let base = self.make_heap_base(func, memory, base_ptr, base_offset, base_fact);
2410+
2411+
Ok(self.heaps.push(HeapData {
2412+
base,
2413+
bound,
2414+
pcc_memory_type,
2415+
memory,
2416+
}))
2417+
}
2418+
2419+
pub(crate) fn make_heap_base(
2420+
&self,
2421+
func: &mut Function,
2422+
memory: Memory,
2423+
ptr: ir::GlobalValue,
2424+
offset: i32,
2425+
fact: Option<Fact>,
2426+
) -> ir::GlobalValue {
2427+
let pointer_type = self.pointer_type();
2428+
2429+
let mut flags = ir::MemFlags::trusted().with_checked().with_can_move();
2430+
if !memory.memory_may_move(self.tunables) {
2431+
flags.set_readonly();
2432+
}
2433+
2434+
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
2435+
base: ptr,
2436+
offset: Offset32::new(offset),
2437+
global_type: pointer_type,
2438+
flags,
2439+
});
2440+
func.global_value_facts[heap_base] = fact;
2441+
heap_base
2442+
}
2443+
2444+
pub(crate) fn make_pcc_base_fact_and_type_for_memory(
2445+
&mut self,
2446+
func: &mut Function,
2447+
memory: Memory,
2448+
base_offset: i32,
2449+
current_length_offset: i32,
2450+
ptr_memtype: Option<ir::MemoryType>,
2451+
heap_bound: ir::GlobalValue,
2452+
) -> (Option<Fact>, Option<ir::MemoryType>) {
23902453
// If we have a declared maximum, we can make this a "static" heap, which is
23912454
// allocated up front and never moved.
23922455
let host_page_size_log2 = self.target_config().page_size_align_log2;
@@ -2493,25 +2556,7 @@ impl FuncEnvironment<'_> {
24932556
(None, None)
24942557
}
24952558
};
2496-
2497-
let mut flags = MemFlags::trusted().with_checked().with_can_move();
2498-
if !memory.memory_may_move(self.tunables) {
2499-
flags.set_readonly();
2500-
}
2501-
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
2502-
base: ptr,
2503-
offset: Offset32::new(base_offset),
2504-
global_type: pointer_type,
2505-
flags,
2506-
});
2507-
func.global_value_facts[heap_base] = base_fact;
2508-
2509-
Ok(self.heaps.push(HeapData {
2510-
base: heap_base,
2511-
bound: heap_bound,
2512-
pcc_memory_type: memory_type,
2513-
memory,
2514-
}))
2559+
(base_fact, memory_type)
25152560
}
25162561

25172562
pub fn make_global(
@@ -3080,15 +3125,11 @@ impl FuncEnvironment<'_> {
30803125
Ok(())
30813126
}
30823127

3083-
pub fn before_unconditionally_trapping_memory_access(
3084-
&mut self,
3085-
builder: &mut FunctionBuilder,
3086-
) -> WasmResult<()> {
3128+
pub fn before_unconditionally_trapping_memory_access(&mut self, builder: &mut FunctionBuilder) {
30873129
if self.tunables.consume_fuel {
30883130
self.fuel_increment_var(builder);
30893131
self.fuel_save_from_var(builder);
30903132
}
3091-
Ok(())
30923133
}
30933134

30943135
pub fn before_translate_function(

crates/cranelift/src/translate/code_translator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,7 +3203,7 @@ fn prepare_addr(
32033203
// If our offset fits within a u32, then we can place the it into the
32043204
// offset immediate of the `heap_addr` instruction.
32053205
Ok(offset) => {
3206-
bounds_check_and_compute_addr(builder, environ, &heap, index, offset, access_size)?
3206+
bounds_check_and_compute_addr(builder, environ, &heap, index, offset, access_size)
32073207
}
32083208

32093209
// If the offset doesn't fit within a u32, then we can't pass it
@@ -3242,7 +3242,7 @@ fn prepare_addr(
32423242
offset,
32433243
ir::TrapCode::HEAP_OUT_OF_BOUNDS,
32443244
);
3245-
bounds_check_and_compute_addr(builder, environ, &heap, adjusted_index, 0, access_size)?
3245+
bounds_check_and_compute_addr(builder, environ, &heap, adjusted_index, 0, access_size)
32463246
}
32473247
};
32483248
let addr = match addr {

0 commit comments

Comments
 (0)