Merge pull request #1692 from alexcrichton/fix-anyref-bugs

Fix a number of `anyref` related bugs in our passes
This commit is contained in:
Alex Crichton 2019-08-02 09:47:14 -05:00 committed by GitHub
commit 117fce1c82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 64 deletions

View File

@ -254,10 +254,6 @@ impl Transform<'_> {
// functions and make sure everything is still hooked up right. // functions and make sure everything is still hooked up right.
self.rewrite_calls(module); self.rewrite_calls(module);
// Inject initialization routine to set up default slots in the table
// (things like null/undefined/true/false)
self.inject_initialization(module);
Ok(()) Ok(())
} }
@ -514,14 +510,14 @@ impl Transform<'_> {
// Store an anyref at an offset from our function's stack // Store an anyref at an offset from our function's stack
// pointer frame. // pointer frame.
let get_fp = builder.local_get(fp); let get_fp = builder.local_get(fp);
next_stack_offset += 1; let (index, idx_local) = if next_stack_offset == 0 {
let (index, idx_local) = if next_stack_offset == 1 {
(get_fp, fp) (get_fp, fp)
} else { } else {
let rhs = builder.i32_const(next_stack_offset); let rhs = builder.i32_const(next_stack_offset);
let add = builder.binop(BinaryOp::I32Add, get_fp, rhs); let add = builder.binop(BinaryOp::I32Add, get_fp, rhs);
(builder.local_tee(scratch_i32, add), scratch_i32) (builder.local_tee(scratch_i32, add), scratch_i32)
}; };
next_stack_offset += 1;
let store = builder.table_set(self.table, index, local); let store = builder.table_set(self.table, index, local);
let get = builder.local_get(idx_local); let get = builder.local_get(idx_local);
builder.with_side_effects(vec![store], get, Vec::new()) builder.with_side_effects(vec![store], get, Vec::new())
@ -669,31 +665,4 @@ impl Transform<'_> {
} }
} }
} }
// Ensure that the `start` function for this module calls the
// `__wbindgen_init_anyref_table` function. This'll ensure that all
// instances of this module have the initial slots of the anyref table
// initialized correctly.
fn inject_initialization(&mut self, module: &mut Module) {
let ty = module.types.add(&[], &[]);
let (import, _) = module.add_import_func(
"__wbindgen_placeholder__",
"__wbindgen_init_anyref_table",
ty,
);
let prev_start = match module.start {
Some(f) => f,
None => {
module.start = Some(import);
return;
}
};
let mut builder = walrus::FunctionBuilder::new();
let call_init = builder.call(import, Box::new([]));
let call_prev = builder.call(prev_start, Box::new([]));
let new_start = builder.finish(ty, Vec::new(), vec![call_init, call_prev], module);
module.start = Some(new_start);
}
} }

View File

@ -145,7 +145,7 @@ intrinsics! {
#[symbol = "__wbindgen_anyref_heap_live_count"] #[symbol = "__wbindgen_anyref_heap_live_count"]
#[signature = fn() -> I32] #[signature = fn() -> I32]
AnyrefHeapLiveCount, AnyrefHeapLiveCount,
#[symbol = "__wbindgen_init_nyref_table"] #[symbol = "__wbindgen_init_anyref_table"]
#[signature = fn() -> Unit] #[signature = fn() -> Unit]
InitAnyrefTable, InitAnyrefTable,
} }

View File

@ -194,10 +194,7 @@ impl<'a> Context<'a> {
// up we always remove the `start` function if one is present. The JS // up we always remove the `start` function if one is present. The JS
// bindings glue then manually calls the start function (if it was // bindings glue then manually calls the start function (if it was
// previously present). // previously present).
let mut needs_manual_start = false; let needs_manual_start = self.unstart_start_function();
if self.config.emit_start {
needs_manual_start = self.unstart_start_function();
}
// After all we've done, especially // After all we've done, especially
// `unexport_unused_internal_exports()`, we probably have a bunch of // `unexport_unused_internal_exports()`, we probably have a bunch of
@ -517,7 +514,10 @@ impl<'a> Context<'a> {
for (i, extra) in extra_modules.iter().enumerate() { for (i, extra) in extra_modules.iter().enumerate() {
let imports = match &mut imports { let imports = match &mut imports {
Some(list) => list, Some(list) => list,
None => bail!("cannot import from modules (`{}`) with `--no-modules`", extra), None => bail!(
"cannot import from modules (`{}`) with `--no-modules`",
extra
),
}; };
imports.push_str(&format!("import * as __wbg_star{} from '{}';\n", i, extra)); imports.push_str(&format!("import * as __wbg_star{} from '{}';\n", i, extra));
imports_init.push_str(&format!("imports['{}'] = __wbg_star{};\n", extra, i)); imports_init.push_str(&format!("imports['{}'] = __wbg_star{};\n", extra, i));
@ -2641,16 +2641,23 @@ impl<'a> Context<'a> {
Intrinsic::InitAnyrefTable => { Intrinsic::InitAnyrefTable => {
self.expose_anyref_table(); self.expose_anyref_table();
String::from(
// Grow the table to insert our initial values, and then also
// set the 0th slot to `undefined` since that's what we've
// historically used for our ABI which is that the index of 0
// returns `undefined` for types like `None` going out.
let mut base = format!(
" "
const table = wasm.__wbg_anyref_table; const table = wasm.__wbg_anyref_table;
const offset = table.grow(4); const offset = table.grow({});
table.set(offset + 0, undefined); table.set(0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
", ",
) INITIAL_HEAP_VALUES.len(),
);
for (i, value) in INITIAL_HEAP_VALUES.iter().enumerate() {
base.push_str(&format!("table.set(offset + {}, {});\n", i, value));
}
base
} }
}; };
Ok(expr) Ok(expr)

View File

@ -313,7 +313,7 @@ impl Bindgen {
// the webidl bindings proposal) as well as an auxiliary section for all // the webidl bindings proposal) as well as an auxiliary section for all
// sorts of miscellaneous information and features #[wasm_bindgen] // sorts of miscellaneous information and features #[wasm_bindgen]
// supports that aren't covered by WebIDL bindings. // supports that aren't covered by WebIDL bindings.
webidl::process(&mut module)?; webidl::process(&mut module, self.anyref, self.emit_start)?;
// Now that we've got type information from the webidl processing pass, // Now that we've got type information from the webidl processing pass,
// touch up the output of rustc to insert anyref shims where necessary. // touch up the output of rustc to insert anyref shims where necessary.
@ -324,12 +324,6 @@ impl Bindgen {
anyref::process(&mut module)?; anyref::process(&mut module)?;
} }
// If we're in a testing mode then remove the start function since we
// shouldn't execute it.
if !self.emit_start {
module.start = None;
}
let aux = module let aux = module
.customs .customs
.delete_typed::<webidl::WasmBindgenAux>() .delete_typed::<webidl::WasmBindgenAux>()

View File

@ -473,10 +473,14 @@ struct Context<'a> {
vendor_prefixes: HashMap<String, Vec<String>>, vendor_prefixes: HashMap<String, Vec<String>>,
unique_crate_identifier: &'a str, unique_crate_identifier: &'a str,
descriptors: HashMap<String, Descriptor>, descriptors: HashMap<String, Descriptor>,
anyref_enabled: bool,
support_start: bool,
} }
pub fn process( pub fn process(
module: &mut Module, module: &mut Module,
anyref_enabled: bool,
support_start: bool,
) -> Result<(NonstandardWebidlSectionId, WasmBindgenAuxId), Error> { ) -> Result<(NonstandardWebidlSectionId, WasmBindgenAuxId), Error> {
let mut storage = Vec::new(); let mut storage = Vec::new();
let programs = extract_programs(module, &mut storage)?; let programs = extract_programs(module, &mut storage)?;
@ -491,6 +495,8 @@ pub fn process(
unique_crate_identifier: "", unique_crate_identifier: "",
module, module,
start_found: false, start_found: false,
anyref_enabled,
support_start,
}; };
cx.init()?; cx.init()?;
@ -532,18 +538,11 @@ impl<'a> Context<'a> {
} }
} }
for (id, intrinsic) in intrinsics { for (id, intrinsic) in intrinsics {
bindings::register_import( self.bind_intrinsic(id, intrinsic)?;
self.module,
&mut self.bindings,
id,
intrinsic.binding(),
ast::WebidlFunctionKind::Static,
)?;
self.aux
.import_map
.insert(id, AuxImport::Intrinsic(intrinsic));
} }
self.inject_anyref_initialization()?;
if let Some(custom) = self if let Some(custom) = self
.module .module
.customs .customs
@ -612,6 +611,48 @@ impl<'a> Context<'a> {
Ok(()) Ok(())
} }
// Ensure that the `start` function for this module calls the
// `__wbindgen_init_anyref_table` function. This'll ensure that all
// instances of this module have the initial slots of the anyref table
// initialized correctly.
fn inject_anyref_initialization(&mut self) -> Result<(), Error> {
if !self.anyref_enabled {
return Ok(());
}
let ty = self.module.types.add(&[], &[]);
let (import, import_id) = self.module.add_import_func(
PLACEHOLDER_MODULE,
"__wbindgen_init_anyref_table",
ty,
);
self.module.start = Some(match self.module.start {
Some(prev_start) => {
let mut builder = walrus::FunctionBuilder::new();
let call_init = builder.call(import, Box::new([]));
let call_prev = builder.call(prev_start, Box::new([]));
builder.finish(ty, Vec::new(), vec![call_init, call_prev], self.module)
}
None => import,
});
self.bind_intrinsic(import_id, Intrinsic::InitAnyrefTable)?;
Ok(())
}
fn bind_intrinsic(&mut self, id: ImportId, intrinsic: Intrinsic) -> Result<(), Error> {
bindings::register_import(
self.module,
&mut self.bindings,
id,
intrinsic.binding(),
ast::WebidlFunctionKind::Static,
)?;
self.aux
.import_map
.insert(id, AuxImport::Intrinsic(intrinsic));
Ok(())
}
fn program(&mut self, program: decode::Program<'a>) -> Result<(), Error> { fn program(&mut self, program: decode::Program<'a>) -> Result<(), Error> {
self.unique_crate_identifier = program.unique_crate_identifier; self.unique_crate_identifier = program.unique_crate_identifier;
let decode::Program { let decode::Program {
@ -752,6 +793,11 @@ impl<'a> Context<'a> {
} }
self.start_found = true; self.start_found = true;
// Skip this when we're generating tests
if !self.support_start {
return Ok(());
}
let prev_start = match self.module.start { let prev_start = match self.module.start {
Some(f) => f, Some(f) => f,
None => { None => {

View File

@ -39,7 +39,7 @@ impl Slab {
internal_error("table grow failure") internal_error("table grow failure")
} }
if self.base == 0 { if self.base == 0 {
self.base = r as usize + (super::JSIDX_RESERVED as usize); self.base = r as usize;
} else if self.base + self.data.len() != r as usize { } else if self.base + self.data.len() != r as usize {
internal_error("someone else allocated table entires?") internal_error("someone else allocated table entires?")
} }