Skip to content

Commit ed24a63

Browse files
authored
Merge pull request #1057 from alexcrichton/start
Add a `#[wasm_bindgen(start)]` attribute
2 parents f4c1c64 + a2aa28e commit ed24a63

File tree

35 files changed

+430
-167
lines changed

35 files changed

+430
-167
lines changed

crates/backend/src/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ pub struct Export {
4646
pub comments: Vec<String>,
4747
/// The name of the rust function/method on the rust side.
4848
pub rust_name: Ident,
49+
/// Whether or not this function should be flagged as the wasm start
50+
/// function.
51+
pub start: bool,
4952
}
5053

5154
/// The 3 types variations of `self`.

crates/backend/src/codegen.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,12 +450,21 @@ impl TryToTokens for ast::Export {
450450
let argtys = self.function.arguments.iter().map(|arg| &arg.ty);
451451
let attrs = &self.function.rust_attrs;
452452

453+
let start_check = if self.start {
454+
quote! {
455+
const _ASSERT: fn() = || #ret_ty { loop {} };
456+
}
457+
} else {
458+
quote! {}
459+
};
460+
453461
(quote! {
454462
#(#attrs)*
455463
#[export_name = #export_name]
456464
#[allow(non_snake_case)]
457465
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
458466
pub extern "C" fn #generated_name(#(#args),*) #ret_ty {
467+
#start_check
459468
// Scope all local variables to be destroyed after we call the
460469
// function to ensure that `#convert_ret`, if it panics, doesn't
461470
// leak anything.

crates/backend/src/encode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ fn shared_export<'a>(export: &'a ast::Export, intern: &'a Interner) -> Export<'a
8282
is_constructor: export.is_constructor,
8383
function: shared_function(&export.function, intern),
8484
comments: export.comments.iter().map(|s| &**s).collect(),
85+
start: export.start,
8586
}
8687
}
8788

crates/cli-support/src/js/closures.rs

Lines changed: 16 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use parity_wasm::elements::*;
1818
use descriptor::Descriptor;
1919
use js::js2rust::Js2Rust;
2020
use js::Context;
21+
use wasm_utils::Remap;
2122

2223
pub fn rewrite(input: &mut Context) -> Result<(), Error> {
2324
let info = ClosureDescriptors::new(input);
@@ -37,15 +38,21 @@ pub fn rewrite(input: &mut Context) -> Result<(), Error> {
3738
// function indices. We're going to be injecting a few imported functions
3839
// below which will shift the index space for all defined functions.
3940
input.parse_wasm_names();
40-
Remap {
41-
code_idx_to_descriptor: &info.code_idx_to_descriptor,
42-
old_num_imports: input
43-
.module
44-
.import_section()
45-
.map(|s| s.functions())
46-
.unwrap_or(0) as u32,
47-
}
48-
.remap_module(input.module);
41+
let old_num_imports = input
42+
.module
43+
.import_section()
44+
.map(|s| s.functions())
45+
.unwrap_or(0) as u32;
46+
Remap(|idx| {
47+
// If this was an imported function we didn't reorder those, so nothing
48+
// to do.
49+
if idx < old_num_imports {
50+
return idx
51+
}
52+
// ... otherwise we're injecting a number of new imports, so offset
53+
// everything.
54+
idx + info.code_idx_to_descriptor.len() as u32
55+
}).remap_module(input.module);
4956

5057
info.delete_function_table_entries(input);
5158
info.inject_imports(input)?;
@@ -298,119 +305,3 @@ impl ClosureDescriptors {
298305
}
299306
}
300307
}
301-
302-
struct Remap<'a> {
303-
code_idx_to_descriptor: &'a BTreeMap<u32, DescribeInstruction>,
304-
old_num_imports: u32,
305-
}
306-
307-
impl<'a> Remap<'a> {
308-
fn remap_module(&self, module: &mut Module) {
309-
for section in module.sections_mut() {
310-
match section {
311-
Section::Export(e) => self.remap_export_section(e),
312-
Section::Element(e) => self.remap_element_section(e),
313-
Section::Code(e) => self.remap_code_section(e),
314-
Section::Start(i) => {
315-
self.remap_idx(i);
316-
}
317-
Section::Name(n) => self.remap_name_section(n),
318-
_ => {}
319-
}
320-
}
321-
}
322-
323-
fn remap_export_section(&self, section: &mut ExportSection) {
324-
for entry in section.entries_mut() {
325-
self.remap_export_entry(entry);
326-
}
327-
}
328-
329-
fn remap_export_entry(&self, entry: &mut ExportEntry) {
330-
match entry.internal_mut() {
331-
Internal::Function(i) => {
332-
self.remap_idx(i);
333-
}
334-
_ => {}
335-
}
336-
}
337-
338-
fn remap_element_section(&self, section: &mut ElementSection) {
339-
for entry in section.entries_mut() {
340-
self.remap_element_entry(entry);
341-
}
342-
}
343-
344-
fn remap_element_entry(&self, entry: &mut ElementSegment) {
345-
for member in entry.members_mut() {
346-
self.remap_idx(member);
347-
}
348-
}
349-
350-
fn remap_code_section(&self, section: &mut CodeSection) {
351-
for body in section.bodies_mut() {
352-
self.remap_func_body(body);
353-
}
354-
}
355-
356-
fn remap_func_body(&self, body: &mut FuncBody) {
357-
self.remap_instructions(body.code_mut());
358-
}
359-
360-
fn remap_instructions(&self, code: &mut Instructions) {
361-
for instr in code.elements_mut() {
362-
self.remap_instruction(instr);
363-
}
364-
}
365-
366-
fn remap_instruction(&self, instr: &mut Instruction) {
367-
match instr {
368-
Instruction::Call(i) => {
369-
self.remap_idx(i);
370-
}
371-
_ => {}
372-
}
373-
}
374-
375-
fn remap_name_section(&self, names: &mut NameSection) {
376-
match names {
377-
NameSection::Function(f) => self.remap_function_name_section(f),
378-
NameSection::Local(f) => self.remap_local_name_section(f),
379-
_ => {}
380-
}
381-
}
382-
383-
fn remap_function_name_section(&self, names: &mut FunctionNameSection) {
384-
let map = names.names_mut();
385-
let new = IndexMap::with_capacity(map.len());
386-
for (mut idx, name) in mem::replace(map, new) {
387-
if !self.remap_idx(&mut idx) {
388-
map.insert(idx, name);
389-
}
390-
}
391-
}
392-
393-
fn remap_local_name_section(&self, names: &mut LocalNameSection) {
394-
let map = names.local_names_mut();
395-
let new = IndexMap::with_capacity(map.len());
396-
for (mut idx, name) in mem::replace(map, new) {
397-
if !self.remap_idx(&mut idx) {
398-
map.insert(idx, name);
399-
}
400-
}
401-
}
402-
403-
/// Returns whether `idx` pointed to a previously known descriptor function
404-
/// that we're switching to an import
405-
fn remap_idx(&self, idx: &mut u32) -> bool {
406-
// If this was an imported function we didn't reorder those, so nothing
407-
// to do.
408-
if *idx < self.old_num_imports {
409-
return false;
410-
}
411-
// ... otherwise we're injecting a number of new imports, so offset
412-
// everything.
413-
*idx += self.code_idx_to_descriptor.len() as u32;
414-
false
415-
}
416-
}

0 commit comments

Comments
 (0)