mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 02:35:41 +00:00
Bug 1505777: [Cranelift] Update to Cranelift 0.23. r=bbouvier
This commit is contained in:
parent
237a48fbb3
commit
018ae56959
@ -8,9 +8,9 @@ crate-type = ["rlib"]
|
||||
name = "baldrdash"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = "0.20.0"
|
||||
cranelift-wasm = "0.20.1"
|
||||
target-lexicon = "0.0.3"
|
||||
cranelift-codegen = "0.23.0"
|
||||
cranelift-wasm = "0.23.0"
|
||||
target-lexicon = "0.2.0"
|
||||
log = { version = "0.4.4", default-features = false, features = ["release_max_level_info"] }
|
||||
env_logger = "0.5.6"
|
||||
|
||||
|
@ -16,9 +16,6 @@
|
||||
// Safe wrappers to the low-level ABI. This re-exports all types in
|
||||
// baldrapi but none of the functions.
|
||||
|
||||
// TODO: Should many u32 arguments and return values here really be
|
||||
// usize, to be more conventional?
|
||||
|
||||
use baldrapi::CraneliftModuleEnvironment;
|
||||
use cranelift_codegen::binemit::CodeOffset;
|
||||
use cranelift_codegen::cursor::{Cursor, FuncCursor};
|
||||
@ -200,13 +197,13 @@ impl<'a> ModuleEnvironment<'a> {
|
||||
unsafe { baldrapi::env_func_is_import(self.env, func_index.index()) }
|
||||
}
|
||||
pub fn signature(&self, sig_index: SignatureIndex) -> FuncTypeWithId {
|
||||
FuncTypeWithId(unsafe { baldrapi::env_signature(self.env, sig_index) })
|
||||
FuncTypeWithId(unsafe { baldrapi::env_signature(self.env, sig_index.index()) })
|
||||
}
|
||||
pub fn table(&self, table_index: TableIndex) -> TableDesc {
|
||||
TableDesc(unsafe { baldrapi::env_table(self.env, table_index) })
|
||||
TableDesc(unsafe { baldrapi::env_table(self.env, table_index.index()) })
|
||||
}
|
||||
pub fn global(&self, global_index: GlobalIndex) -> GlobalDesc {
|
||||
GlobalDesc(unsafe { baldrapi::env_global(self.env, global_index) })
|
||||
GlobalDesc(unsafe { baldrapi::env_global(self.env, global_index.index()) })
|
||||
}
|
||||
pub fn min_memory_length(&self) -> i64 {
|
||||
self.env.min_memory_length as i64
|
||||
|
@ -92,9 +92,8 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
|
||||
}
|
||||
|
||||
pub fn compile(&mut self) -> CodegenResult<()> {
|
||||
let orig_size = self.context.compile(&*self.isa)?;
|
||||
let size = self.remove_return_inst(orig_size) as usize;
|
||||
self.binemit(size)
|
||||
let size = self.context.compile(&*self.isa)?;
|
||||
self.binemit(size as usize)
|
||||
}
|
||||
|
||||
/// Translate the WebAssembly code to Cranelift IR.
|
||||
@ -119,37 +118,6 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
|
||||
Ok(wsig)
|
||||
}
|
||||
|
||||
/// Remove the trailing return instruction from the current function to make room for a custom
|
||||
/// epilogue.
|
||||
///
|
||||
/// Return the new function size in bytes, adjusted from size.
|
||||
fn remove_return_inst(&mut self, size: CodeOffset) -> CodeOffset {
|
||||
// Get the last instruction in the function.
|
||||
let mut pos = FuncCursor::new(&mut self.context.func);
|
||||
|
||||
// Move to the bottom of the last EBB in the function.
|
||||
pos.prev_ebb().expect("empty function");
|
||||
|
||||
// Move to the last instruction in the last EBB.
|
||||
let inst = pos.prev_inst().expect("last EBB has not terminator");
|
||||
|
||||
// TODO There might be an issue here, if there can be more than one
|
||||
// IR returns per IR function.
|
||||
|
||||
if pos.func.dfg[inst].opcode().is_return() {
|
||||
let enc = pos.func.encodings[inst];
|
||||
let ret_size = self.isa.encoding_info().bytes(enc);
|
||||
// Remove the return instruction. This leaves the IR in an invalid state where the last
|
||||
// EBB has no terminator. The code emitter shouldn't mind this. If it does want to
|
||||
// verify the IR in the future, we could use a zero-sized return encoding instead.
|
||||
pos.remove_inst();
|
||||
return size - ret_size;
|
||||
}
|
||||
|
||||
// Function doesn't have a return instruction.
|
||||
size
|
||||
}
|
||||
|
||||
/// Emit binary machine code to `emitter`.
|
||||
fn binemit(&mut self, size: usize) -> CodegenResult<()> {
|
||||
let frame_pushed = self.frame_pushed();
|
||||
|
@ -33,22 +33,13 @@ use baldrdash::StaticEnvironment;
|
||||
|
||||
impl From<isa::LookupError> for BasicError {
|
||||
fn from(err: isa::LookupError) -> BasicError {
|
||||
let msg = match err {
|
||||
isa::LookupError::SupportDisabled => "ISA support is disabled",
|
||||
isa::LookupError::Unsupported => "unsupported ISA",
|
||||
};
|
||||
BasicError::new(msg.to_string())
|
||||
BasicError::new(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<settings::SetError> for BasicError {
|
||||
fn from(err: settings::SetError) -> BasicError {
|
||||
let msg = match err {
|
||||
settings::SetError::BadName => "bad setting name",
|
||||
settings::SetError::BadType => "bad setting type",
|
||||
settings::SetError::BadValue => "bad setting value",
|
||||
};
|
||||
BasicError::new(msg.to_string())
|
||||
BasicError::new(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,10 +94,6 @@ pub fn make_isa(env: &StaticEnvironment) -> DashResult<Box<isa::TargetIsa>> {
|
||||
fn make_shared_flags() -> settings::SetResult<settings::Flags> {
|
||||
let mut sb = settings::builder();
|
||||
|
||||
// Since we're using SM's epilogue insertion code, we can only handle a single return
|
||||
// instruction at the end of the function.
|
||||
sb.enable("return_at_end")?;
|
||||
|
||||
// We don't install SIGFPE handlers, but depend on explicit traps around divisions.
|
||||
sb.enable("avoid_div_traps")?;
|
||||
|
||||
@ -135,5 +122,8 @@ fn make_shared_flags() -> settings::SetResult<settings::Flags> {
|
||||
// Let's optimize for speed.
|
||||
sb.set("opt_level", "best")?;
|
||||
|
||||
// TODO: Enable jump tables (requires emitting readonly data separately from text).
|
||||
sb.set("jump_tables_enabled", "false")?;
|
||||
|
||||
Ok(settings::Flags::new(sb))
|
||||
}
|
||||
|
@ -21,15 +21,15 @@
|
||||
use baldrdash as bd;
|
||||
use compile::{symbolic_function_name, wasm_function_name};
|
||||
use cranelift_codegen::cursor::{Cursor, FuncCursor};
|
||||
use cranelift_codegen::entity::EntityMap;
|
||||
use cranelift_codegen::entity::{EntityRef, PrimaryMap, SecondaryMap};
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_codegen::ir::condcodes::IntCC;
|
||||
use cranelift_codegen::ir::InstBuilder;
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::isa::{CallConv, TargetFrontendConfig, TargetIsa};
|
||||
use cranelift_codegen::packed_option::PackedOption;
|
||||
use cranelift_codegen::settings::{CallConv, Flags};
|
||||
use cranelift_codegen::settings::Flags;
|
||||
use cranelift_wasm::{
|
||||
self, FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex, WasmResult,
|
||||
self, FuncIndex, GlobalIndex, MemoryIndex, ReturnMode, SignatureIndex, TableIndex, WasmResult,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use target_lexicon::Triple;
|
||||
@ -58,6 +58,11 @@ fn offset32(offset: usize) -> ir::immediates::Offset32 {
|
||||
(offset as i32).into()
|
||||
}
|
||||
|
||||
/// Convert a usize offset into a `Imm64` for an iadd_imm.
|
||||
fn imm64(offset: usize) -> ir::immediates::Imm64 {
|
||||
(offset as i64).into()
|
||||
}
|
||||
|
||||
/// Initialize a `Signature` from a wasm signature.
|
||||
fn init_sig_from_wsig(sig: &mut ir::Signature, wsig: bd::FuncTypeWithId) {
|
||||
sig.clear(CallConv::Baldrdash);
|
||||
@ -102,7 +107,7 @@ pub struct TransEnv<'a, 'b, 'c> {
|
||||
|
||||
/// Information about the function pointer tables `self.env` knowns about. Indexed by table
|
||||
/// index.
|
||||
tables: Vec<TableInfo>,
|
||||
tables: PrimaryMap<TableIndex, TableInfo>,
|
||||
|
||||
/// For those signatures whose ID is stored in a global, keep track of the globals we have
|
||||
/// created so far.
|
||||
@ -118,7 +123,10 @@ pub struct TransEnv<'a, 'b, 'c> {
|
||||
/// imported functions are numbered starting from 0.
|
||||
///
|
||||
/// Any `None` entries in this table are simply global variables that have not yet been created.
|
||||
func_gvs: EntityMap<FuncIndex, PackedOption<ir::GlobalValue>>,
|
||||
func_gvs: SecondaryMap<FuncIndex, PackedOption<ir::GlobalValue>>,
|
||||
|
||||
/// The `vmctx` global value.
|
||||
vmctx_gv: PackedOption<ir::GlobalValue>,
|
||||
|
||||
/// Global variable representing the `TlsData::instance` field which points to the current
|
||||
/// instance.
|
||||
@ -149,9 +157,10 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
isa,
|
||||
env,
|
||||
static_env,
|
||||
tables: Vec::new(),
|
||||
tables: PrimaryMap::new(),
|
||||
signatures: HashMap::new(),
|
||||
func_gvs: EntityMap::new(),
|
||||
func_gvs: SecondaryMap::new(),
|
||||
vmctx_gv: None.into(),
|
||||
instance_gv: None.into(),
|
||||
interrupt_gv: None.into(),
|
||||
symbolic: [None.into(); 2],
|
||||
@ -160,22 +169,39 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `vmctx` global value.
|
||||
fn get_vmctx_gv(&mut self, func: &mut ir::Function) -> ir::GlobalValue {
|
||||
match self.vmctx_gv.expand() {
|
||||
Some(gv) => gv,
|
||||
None => {
|
||||
// We need to allocate the global variable.
|
||||
let gv = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
self.vmctx_gv = Some(gv).into();
|
||||
gv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get information about `table`.
|
||||
/// Create it if necessary.
|
||||
fn get_table(&mut self, func: &mut ir::Function, table: TableIndex) -> TableInfo {
|
||||
// Allocate all tables up to the requested index.
|
||||
while self.tables.len() <= table {
|
||||
let wtab = self.env.table(self.tables.len());
|
||||
self.tables.push(TableInfo::new(wtab, func));
|
||||
let vmctx = self.get_vmctx_gv(func);
|
||||
while self.tables.len() <= table.index() {
|
||||
let wtab = self.env.table(TableIndex::new(self.tables.len()));
|
||||
self.tables.push(TableInfo::new(wtab, func, vmctx));
|
||||
}
|
||||
self.tables[table].clone()
|
||||
}
|
||||
|
||||
/// Get the global variable storing the ID of the given signature.
|
||||
fn sig_global(&mut self, func: &mut ir::Function, offset: usize) -> ir::GlobalValue {
|
||||
let vmctx = self.get_vmctx_gv(func);
|
||||
*self.signatures.entry(offset as i32).or_insert_with(|| {
|
||||
func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(offset),
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(offset),
|
||||
global_type: native_pointer_type(),
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -187,8 +213,11 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
return gv;
|
||||
}
|
||||
// We need to create a global variable for `import_index`.
|
||||
let gv = func.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(self.env.func_import_tls_offset(index)),
|
||||
let vmctx = self.get_vmctx_gv(func);
|
||||
let gv = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(self.env.func_import_tls_offset(index)),
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
// Save it for next time.
|
||||
self.func_gvs[index] = gv.into();
|
||||
@ -201,11 +230,12 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
Some(gv) => gv,
|
||||
None => {
|
||||
// We need to allocate the global variable.
|
||||
let gv = pos
|
||||
.func
|
||||
.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(self.static_env.instanceTlsOffset),
|
||||
});
|
||||
let vmctx = self.get_vmctx_gv(pos.func);
|
||||
let gv = pos.func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(self.static_env.instanceTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
self.instance_gv = gv.into();
|
||||
gv
|
||||
}
|
||||
@ -221,11 +251,12 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
Some(gv) => gv,
|
||||
None => {
|
||||
// We need to allocate the global variable.
|
||||
let gv = pos
|
||||
.func
|
||||
.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(self.static_env.interruptTlsOffset),
|
||||
});
|
||||
let vmctx = self.get_vmctx_gv(pos.func);
|
||||
let gv = pos.func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(self.static_env.interruptTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
self.interrupt_gv = gv.into();
|
||||
gv
|
||||
}
|
||||
@ -264,17 +295,23 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
/// realm value, in case the call has used a different realm.
|
||||
fn switch_to_wasm_tls_realm(&mut self, pos: &mut FuncCursor) {
|
||||
if self.cx_addr.is_none() {
|
||||
let vmctx = self.get_vmctx_gv(&mut pos.func);
|
||||
self.cx_addr = pos
|
||||
.func
|
||||
.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(self.static_env.cxTlsOffset),
|
||||
.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(self.static_env.cxTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
}).into();
|
||||
}
|
||||
if self.realm_addr.is_none() {
|
||||
let vmctx = self.get_vmctx_gv(&mut pos.func);
|
||||
self.realm_addr = pos
|
||||
.func
|
||||
.create_global_value(ir::GlobalValueData::VMContext {
|
||||
offset: offset32(self.static_env.realmTlsOffset),
|
||||
.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset: imm64(self.static_env.realmTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
}).into();
|
||||
}
|
||||
|
||||
@ -337,12 +374,8 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
fn flags(&self) -> &Flags {
|
||||
self.isa.flags()
|
||||
}
|
||||
|
||||
fn triple(&self) -> &Triple {
|
||||
self.isa.triple()
|
||||
fn target_config(&self) -> TargetFrontendConfig {
|
||||
self.isa.frontend_config()
|
||||
}
|
||||
|
||||
fn pointer_type(&self) -> ir::Type {
|
||||
@ -364,16 +397,23 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
cranelift_wasm::GlobalVariable::Const(global.emit_constant(&mut pos))
|
||||
} else {
|
||||
// This is a global variable. Here we don't care if it is mutable or not.
|
||||
let offset = offset32(global.tls_offset());
|
||||
let mut gv = func.create_global_value(ir::GlobalValueData::VMContext { offset });
|
||||
let offset = global.tls_offset();
|
||||
let mut gv = self.get_vmctx_gv(func);
|
||||
|
||||
// Some globals are represented as a pointer to the actual data, in which case we
|
||||
// must do an extra dereference to get to them.
|
||||
if global.is_indirect() {
|
||||
gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: gv,
|
||||
offset: offset32(0),
|
||||
memory_type: native_pointer_type(),
|
||||
offset: offset32(offset),
|
||||
global_type: native_pointer_type(),
|
||||
readonly: false,
|
||||
});
|
||||
} else {
|
||||
gv = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: gv,
|
||||
offset: imm64(offset),
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -387,18 +427,19 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
}
|
||||
|
||||
fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap {
|
||||
assert_eq!(index, 0, "Only one WebAssembly memory supported");
|
||||
assert_eq!(index.index(), 0, "Only one WebAssembly memory supported");
|
||||
// Get the address of the `TlsData::memoryBase` field.
|
||||
let base_addr =
|
||||
func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
|
||||
// Get the `TlsData::memoryBase` field.
|
||||
let base = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
let base_addr = self.get_vmctx_gv(func);
|
||||
// Get the `TlsData::memoryBase` field. We assume this is never modified during execution
|
||||
// of the function.
|
||||
let base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: base_addr,
|
||||
offset: offset32(0),
|
||||
memory_type: native_pointer_type(),
|
||||
global_type: native_pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
let min_size = ir::immediates::Imm64::new(self.env.min_memory_length());
|
||||
let guard_size = ir::immediates::Imm64::new(self.static_env.memoryGuardSize as i64);
|
||||
let guard_size = imm64(self.static_env.memoryGuardSize);
|
||||
|
||||
let bound = self.static_env.staticMemoryBound;
|
||||
let style = if bound > 0 {
|
||||
@ -406,14 +447,12 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
let bound = (bound as i64).into();
|
||||
ir::HeapStyle::Static { bound }
|
||||
} else {
|
||||
let offset = native_pointer_size().into();
|
||||
// Get the address of the `TlsData::boundsCheckLimit` field.
|
||||
let bound_gv_addr = func.create_global_value(ir::GlobalValueData::VMContext { offset });
|
||||
// Get the `TlsData::boundsCheckLimit` field.
|
||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
base: bound_gv_addr,
|
||||
offset: offset32(0),
|
||||
memory_type: ir::types::I32,
|
||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: base_addr,
|
||||
offset: native_pointer_size().into(),
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
ir::HeapStyle::Dynamic { bound_gv }
|
||||
};
|
||||
@ -448,16 +487,18 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
|
||||
// TODO we'd need a better way to synchronize the shape of GlobalDataDesc and these
|
||||
// offsets.
|
||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_desc.global,
|
||||
offset: 0.into(),
|
||||
memory_type: ir::types::I32,
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
let base_gv = func.create_global_value(ir::GlobalValueData::Deref {
|
||||
let base_gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_desc.global,
|
||||
offset: native_pointer_size().into(),
|
||||
memory_type: native_pointer_type(),
|
||||
offset: offset32(native_pointer_size() as usize),
|
||||
global_type: native_pointer_type(),
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
@ -496,7 +537,7 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
|
||||
// TODO: When compiling asm.js, the table index in inferred from the signature index.
|
||||
// Currently, WebAssembly doesn't support multiple tables. That may change.
|
||||
assert_eq!(table_index, 0);
|
||||
assert_eq!(table_index.index(), 0);
|
||||
let wtable = self.get_table(pos.func, table_index);
|
||||
|
||||
// Follows `MacroAssembler::wasmCallIndirect`:
|
||||
@ -586,7 +627,7 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
|
||||
let call = pos
|
||||
.ins()
|
||||
.CallIndirect(ir::Opcode::CallIndirect, ir::types::VOID, sig_ref, args)
|
||||
.CallIndirect(ir::Opcode::CallIndirect, ir::types::INVALID, sig_ref, args)
|
||||
.0;
|
||||
self.switch_to_wasm_tls_realm(&mut pos);
|
||||
Ok(call)
|
||||
@ -636,7 +677,7 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
let sig = pos.func.dfg.ext_funcs[callee].signature;
|
||||
let call = pos
|
||||
.ins()
|
||||
.CallIndirect(ir::Opcode::CallIndirect, ir::types::VOID, sig, args)
|
||||
.CallIndirect(ir::Opcode::CallIndirect, ir::types::INVALID, sig, args)
|
||||
.0;
|
||||
self.switch_to_wasm_tls_realm(&mut pos);
|
||||
Ok(call)
|
||||
@ -652,7 +693,7 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
|
||||
Ok(pos
|
||||
.ins()
|
||||
.Call(ir::Opcode::Call, ir::types::VOID, callee, args)
|
||||
.Call(ir::Opcode::Call, ir::types::INVALID, callee, args)
|
||||
.0)
|
||||
}
|
||||
}
|
||||
@ -732,6 +773,12 @@ impl<'a, 'b, 'c> cranelift_wasm::FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
||||
let interrupt = self.load_interrupt_flag(&mut pos);
|
||||
pos.ins().trapnz(interrupt, ir::TrapCode::Interrupt);
|
||||
}
|
||||
|
||||
fn return_mode(&self) -> ReturnMode {
|
||||
// Since we're using SM's epilogue insertion code, we can only handle a single return
|
||||
// instruction at the end of the function.
|
||||
ReturnMode::FallthroughReturn
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a function table.
|
||||
@ -749,12 +796,16 @@ struct TableInfo {
|
||||
|
||||
impl TableInfo {
|
||||
/// Create a TableInfo and its global variable in `func`.
|
||||
pub fn new(wtab: bd::TableDesc, func: &mut ir::Function) -> TableInfo {
|
||||
pub fn new(wtab: bd::TableDesc, func: &mut ir::Function, vmctx: ir::GlobalValue) -> TableInfo {
|
||||
// Create the global variable.
|
||||
let offset = wtab.tls_offset();
|
||||
assert!(offset < i32::max_value() as usize);
|
||||
let offset = (offset as i32).into();
|
||||
let global = func.create_global_value(ir::GlobalValueData::VMContext { offset });
|
||||
let offset = imm64(offset);
|
||||
let global = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset,
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
|
||||
TableInfo {
|
||||
global,
|
||||
|
Loading…
Reference in New Issue
Block a user