Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Nov 3, 2024
1 parent c2bfcb7 commit e28c8db
Show file tree
Hide file tree
Showing 32 changed files with 665 additions and 958 deletions.
38 changes: 26 additions & 12 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,15 @@ wasmtime_option_group! {
pub opt_level: Option<wasmtime::OptLevel>,

/// Force using a "static" style for all wasm memories
///
/// TODO: deprecated
pub static_memory_forced: Option<bool>,

/// Maximum size in bytes of wasm memory before it becomes dynamically
/// relocatable instead of up-front-reserved.
pub static_memory_maximum_size: Option<u64>,

/// Size, in bytes, of guard pages for linear memories.
pub memory_guard_size: Option<u64>,

/// Bytes to reserve at the end of linear memory for growth for dynamic
/// memories.
pub dynamic_memory_reserved_for_growth: Option<u64>,
/// TODO
pub memory_reservation: Option<u64>,

/// Indicates whether an unmapped region of memory is placed before all
/// linear memories.
Expand Down Expand Up @@ -170,6 +167,18 @@ wasmtime_option_group! {

/// DEPRECATED: Use `-Cmemory-guard-size=N` instead.
pub static_memory_guard_size: Option<u64>,

/// [DEPRECATED] Maximum size in bytes of wasm memory before it becomes
/// dynamically relocatable instead of up-front-reserved.
///
/// Use `-O memory-reservation=N` instead
pub static_memory_maximum_size: Option<u64>,

/// [DEPRECATED] Bytes to reserve at the end of linear memory for growth
/// for dynamic memories.
///
/// Use `-O memory-reservation=N` instead
pub dynamic_memory_reserved_for_growth: Option<u64>,
}

enum Optimize {
Expand Down Expand Up @@ -632,11 +641,19 @@ impl CommonOptions {
}

if let Some(max) = self.opts.static_memory_maximum_size {
config.static_memory_maximum_size(max);
config.memory_reservation(max);
}
if let Some(size) = self.opts.dynamic_memory_reserved_for_growth {
config.memory_reservation(size);
}
if let Some(max) = self.opts.memory_reservation {
config.memory_reservation(max);
}

if let Some(enable) = self.opts.static_memory_forced {
config.static_memory_forced(enable);
let _ = enable;
todo!()
// config.static_memory_forced(enable);
}

if let Some(size) = self
Expand All @@ -648,9 +665,6 @@ impl CommonOptions {
config.memory_guard_size(size);
}

if let Some(size) = self.opts.dynamic_memory_reserved_for_growth {
config.dynamic_memory_reserved_for_growth(size);
}
if let Some(enable) = self.opts.guard_before_linear_memory {
config.guard_before_linear_memory(enable);
}
Expand Down
136 changes: 17 additions & 119 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ use std::mem;
use wasmparser::{Operator, WasmFeatures};
use wasmtime_environ::{
BuiltinFunctionIndex, DataIndex, ElemIndex, EngineOrModuleTypeIndex, FuncIndex, GlobalIndex,
IndexType, Memory, MemoryIndex, MemoryStyle, Module, ModuleInternedTypeIndex,
ModuleTranslation, ModuleTypesBuilder, PtrSize, Table, TableIndex, Tunables, TypeConvert,
TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType,
WasmRefType, WasmResult, WasmValType,
IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex, ModuleTranslation,
ModuleTypesBuilder, PtrSize, Table, TableIndex, Tunables, TypeConvert, TypeIndex, VMOffsets,
WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType, WasmRefType, WasmResult,
WasmValType,
};
use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK};

Expand Down Expand Up @@ -2368,134 +2368,32 @@ impl<'module_environment> crate::translate::FuncEnvironment
flags: MemFlags::trusted(),
});

// If we have a declared maximum, we can make this a "static" heap, which is
// allocated up front and never moved.
let style = MemoryStyle::for_memory(memory, self.tunables);
let (readonly_base, base_fact, memory_type) = match style {
MemoryStyle::Dynamic { .. } => {
let (base_fact, data_mt) = if let Some(ptr_memtype) = ptr_memtype {
// Create a memtype representing the untyped memory region.
let data_mt = func.create_memory_type(ir::MemoryTypeData::DynamicMemory {
gv: heap_bound,
size: self.tunables.memory_guard_size,
});
// This fact applies to any pointer to the start of the memory.
let base_fact = ir::Fact::dynamic_base_ptr(data_mt);
// This fact applies to the length.
let length_fact = ir::Fact::global_value(
u16::try_from(self.isa.pointer_type().bits()).unwrap(),
heap_bound,
);
// Create a field in the vmctx for the base pointer.
match &mut func.memory_types[ptr_memtype] {
ir::MemoryTypeData::Struct { size, fields } => {
let base_offset = u64::try_from(base_offset).unwrap();
fields.push(ir::MemoryTypeField {
offset: base_offset,
ty: self.isa.pointer_type(),
// Read-only field from the PoV of PCC checks:
// don't allow stores to this field. (Even if
// it is a dynamic memory whose base can
// change, that update happens inside the
// runtime, not in generated code.)
readonly: true,
fact: Some(base_fact.clone()),
});
let current_length_offset =
u64::try_from(current_length_offset).unwrap();
fields.push(ir::MemoryTypeField {
offset: current_length_offset,
ty: self.isa.pointer_type(),
// As above, read-only; only the runtime modifies it.
readonly: true,
fact: Some(length_fact),
});

let pointer_size = u64::from(self.isa.pointer_type().bytes());
let fields_end = std::cmp::max(
base_offset + pointer_size,
current_length_offset + pointer_size,
);
*size = std::cmp::max(*size, fields_end);
}
_ => {
panic!("Bad memtype");
}
}
// Apply a fact to the base pointer.
(Some(base_fact), Some(data_mt))
} else {
(None, None)
};

(false, base_fact, data_mt)
}
MemoryStyle::Static {
byte_reservation: bound_bytes,
} => {
let (base_fact, data_mt) = if let Some(ptr_memtype) = ptr_memtype {
// Create a memtype representing the untyped memory region.
let data_mt = func.create_memory_type(ir::MemoryTypeData::Memory {
size: bound_bytes
.checked_add(self.tunables.memory_guard_size)
.expect("Memory plan has overflowing size plus guard"),
});
// This fact applies to any pointer to the start of the memory.
let base_fact = Fact::Mem {
ty: data_mt,
min_offset: 0,
max_offset: 0,
nullable: false,
};
// Create a field in the vmctx for the base pointer.
match &mut func.memory_types[ptr_memtype] {
ir::MemoryTypeData::Struct { size, fields } => {
let offset = u64::try_from(base_offset).unwrap();
fields.push(ir::MemoryTypeField {
offset,
ty: self.isa.pointer_type(),
// Read-only field from the PoV of PCC checks:
// don't allow stores to this field. (Even if
// it is a dynamic memory whose base can
// change, that update happens inside the
// runtime, not in generated code.)
readonly: true,
fact: Some(base_fact.clone()),
});
*size = std::cmp::max(
*size,
offset + u64::from(self.isa.pointer_type().bytes()),
);
}
_ => {
panic!("Bad memtype");
}
}
// Apply a fact to the base pointer.
(Some(base_fact), Some(data_mt))
} else {
(None, None)
};
(true, base_fact, data_mt)
}
};
let _ = ptr_memtype;

// If the maximum byte size of this memory is less than or equal to the
// configured memory reservation for each memory then that means that
// the base pointer won't ever change at runtime. In this situation the
// load of the base pointer can be readonly and, for example, hoisted
// out of loops.
let mut flags = MemFlags::trusted().with_checked();
if readonly_base {
flags.set_readonly();
if let Ok(max) = memory.maximum_byte_size() {
if max <= self.tunables.memory_reservation {
flags.set_readonly();
}
}
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
base: ptr,
offset: Offset32::new(base_offset),
global_type: pointer_type,
flags,
});
func.global_value_facts[heap_base] = base_fact;
// TODO
// func.global_value_facts[heap_base] = base_fact;

Ok(self.heaps.push(HeapData {
base: heap_base,
bound: heap_bound,
pcc_memory_type: memory_type,
pcc_memory_type: None, // TODO
memory,
}))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cranelift/src/translate/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
addr
} else {
let index_type = environ.heaps()[heap].index_type();
let offset = builder.ins().iconst(index_type, memarg.offset as i64);
let offset = builder.ins().iconst(index_type, memarg.offset.signed());
environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
};
// `fn translate_atomic_wait` can inspect the type of `expected` to figure out what
Expand All @@ -1279,7 +1279,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
addr
} else {
let index_type = environ.heaps()[heap].index_type();
let offset = builder.ins().iconst(index_type, memarg.offset as i64);
let offset = builder.ins().iconst(index_type, memarg.offset.signed());
environ.uadd_overflow_trap(builder, addr, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS)
};
let res = environ.translate_atomic_notify(
Expand Down
Loading

0 comments on commit e28c8db

Please sign in to comment.