Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a #[wasm_bindgen(start)] attribute #1057

Merged
merged 1 commit into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub struct Export {
pub comments: Vec<String>,
/// The name of the rust function/method on the rust side.
pub rust_name: Ident,
/// Whether or not this function should be flagged as the wasm start
/// function.
pub start: bool,
}

/// The 3 types variations of `self`.
Expand Down
9 changes: 9 additions & 0 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,12 +450,21 @@ impl TryToTokens for ast::Export {
let argtys = self.function.arguments.iter().map(|arg| &arg.ty);
let attrs = &self.function.rust_attrs;

let start_check = if self.start {
quote! {
const _ASSERT: fn() = || #ret_ty { loop {} };
}
} else {
quote! {}
};

(quote! {
#(#attrs)*
#[export_name = #export_name]
#[allow(non_snake_case)]
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub extern "C" fn #generated_name(#(#args),*) #ret_ty {
#start_check
// Scope all local variables to be destroyed after we call the
// function to ensure that `#convert_ret`, if it panics, doesn't
// leak anything.
Expand Down
1 change: 1 addition & 0 deletions crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ fn shared_export<'a>(export: &'a ast::Export, intern: &'a Interner) -> Export<'a
is_constructor: export.is_constructor,
function: shared_function(&export.function, intern),
comments: export.comments.iter().map(|s| &**s).collect(),
start: export.start,
}
}

Expand Down
141 changes: 16 additions & 125 deletions crates/cli-support/src/js/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use parity_wasm::elements::*;
use descriptor::Descriptor;
use js::js2rust::Js2Rust;
use js::Context;
use wasm_utils::Remap;

pub fn rewrite(input: &mut Context) -> Result<(), Error> {
let info = ClosureDescriptors::new(input);
Expand All @@ -37,15 +38,21 @@ pub fn rewrite(input: &mut Context) -> Result<(), Error> {
// function indices. We're going to be injecting a few imported functions
// below which will shift the index space for all defined functions.
input.parse_wasm_names();
Remap {
code_idx_to_descriptor: &info.code_idx_to_descriptor,
old_num_imports: input
.module
.import_section()
.map(|s| s.functions())
.unwrap_or(0) as u32,
}
.remap_module(input.module);
let old_num_imports = input
.module
.import_section()
.map(|s| s.functions())
.unwrap_or(0) as u32;
Remap(|idx| {
// If this was an imported function we didn't reorder those, so nothing
// to do.
if idx < old_num_imports {
return idx
}
// ... otherwise we're injecting a number of new imports, so offset
// everything.
idx + info.code_idx_to_descriptor.len() as u32
}).remap_module(input.module);

info.delete_function_table_entries(input);
info.inject_imports(input)?;
Expand Down Expand Up @@ -298,119 +305,3 @@ impl ClosureDescriptors {
}
}
}

struct Remap<'a> {
code_idx_to_descriptor: &'a BTreeMap<u32, DescribeInstruction>,
old_num_imports: u32,
}

impl<'a> Remap<'a> {
fn remap_module(&self, module: &mut Module) {
for section in module.sections_mut() {
match section {
Section::Export(e) => self.remap_export_section(e),
Section::Element(e) => self.remap_element_section(e),
Section::Code(e) => self.remap_code_section(e),
Section::Start(i) => {
self.remap_idx(i);
}
Section::Name(n) => self.remap_name_section(n),
_ => {}
}
}
}

fn remap_export_section(&self, section: &mut ExportSection) {
for entry in section.entries_mut() {
self.remap_export_entry(entry);
}
}

fn remap_export_entry(&self, entry: &mut ExportEntry) {
match entry.internal_mut() {
Internal::Function(i) => {
self.remap_idx(i);
}
_ => {}
}
}

fn remap_element_section(&self, section: &mut ElementSection) {
for entry in section.entries_mut() {
self.remap_element_entry(entry);
}
}

fn remap_element_entry(&self, entry: &mut ElementSegment) {
for member in entry.members_mut() {
self.remap_idx(member);
}
}

fn remap_code_section(&self, section: &mut CodeSection) {
for body in section.bodies_mut() {
self.remap_func_body(body);
}
}

fn remap_func_body(&self, body: &mut FuncBody) {
self.remap_instructions(body.code_mut());
}

fn remap_instructions(&self, code: &mut Instructions) {
for instr in code.elements_mut() {
self.remap_instruction(instr);
}
}

fn remap_instruction(&self, instr: &mut Instruction) {
match instr {
Instruction::Call(i) => {
self.remap_idx(i);
}
_ => {}
}
}

fn remap_name_section(&self, names: &mut NameSection) {
match names {
NameSection::Function(f) => self.remap_function_name_section(f),
NameSection::Local(f) => self.remap_local_name_section(f),
_ => {}
}
}

fn remap_function_name_section(&self, names: &mut FunctionNameSection) {
let map = names.names_mut();
let new = IndexMap::with_capacity(map.len());
for (mut idx, name) in mem::replace(map, new) {
if !self.remap_idx(&mut idx) {
map.insert(idx, name);
}
}
}

fn remap_local_name_section(&self, names: &mut LocalNameSection) {
let map = names.local_names_mut();
let new = IndexMap::with_capacity(map.len());
for (mut idx, name) in mem::replace(map, new) {
if !self.remap_idx(&mut idx) {
map.insert(idx, name);
}
}
}

/// Returns whether `idx` pointed to a previously known descriptor function
/// that we're switching to an import
fn remap_idx(&self, idx: &mut u32) -> bool {
// If this was an imported function we didn't reorder those, so nothing
// to do.
if *idx < self.old_num_imports {
return false;
}
// ... otherwise we're injecting a number of new imports, so offset
// everything.
*idx += self.code_idx_to_descriptor.len() as u32;
false
}
}
Loading