diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-05-07 20:43:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-07 20:43:27 +0200 |
commit | 2b66b8a03e4f81cc158be40d07534f26fa762c2b (patch) | |
tree | bdeb6b1e6737bd839c87e2d6d178da42d9004ca4 /cli/compilers/wasm.rs | |
parent | 93cf3bd5341d5985201ea0905280082d5a3310f9 (diff) |
BREAKING: Remove support for .wasm imports (#5135)
Importing .wasm files is non-standardized therefore deciding to
support current functionality past 1.0 release is risky.
Besides that .wasm import posed many challenges in our codebase
due to complex interactions with TS compiler which spawned
thread for each encountered .wasm import.
This commit removes:
- cli/compilers/wasm.rs
- cli/compilers/wasm_wrap.js
- two integration tests related to .wasm imports
Diffstat (limited to 'cli/compilers/wasm.rs')
-rw-r--r-- | cli/compilers/wasm.rs | 185 |
1 files changed, 0 insertions, 185 deletions
diff --git a/cli/compilers/wasm.rs b/cli/compilers/wasm.rs deleted file mode 100644 index ed5603584..000000000 --- a/cli/compilers/wasm.rs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::compiler_worker::CompilerWorker; -use crate::compilers::CompiledModule; -use crate::file_fetcher::SourceFile; -use crate::global_state::GlobalState; -use crate::startup_data; -use crate::state::*; -use crate::tokio_util; -use crate::web_worker::WebWorkerHandle; -use crate::worker::WorkerEvent; -use deno_core::Buf; -use deno_core::ErrBox; -use deno_core::ModuleSpecifier; -use serde_derive::Deserialize; -use std::collections::HashMap; -use std::sync::atomic::Ordering; -use std::sync::{Arc, Mutex}; -use url::Url; - -// TODO(ry) The entire concept of spawning a thread, sending data to JS, -// compiling WASM there, and moving the data back into the calling thread is -// completelly wrong. V8 has native facilities for getting this information. -// We might be lacking bindings for this currently in rusty_v8 but ultimately -// this "compiler" should be calling into rusty_v8 directly, not spawning -// threads. - -// TODO(kevinkassimo): This is a hack to encode/decode data as base64 string. -// (Since Deno namespace might not be available, Deno.read can fail). -// Binary data is already available through source_file.source_code. -// If this is proven too wasteful in practice, refactor this. - -// Ref: https://webassembly.github.io/esm-integration/js-api/index.html#esm-integration -// https://github.com/nodejs/node/blob/35ec01097b2a397ad0a22aac536fe07514876e21/lib/internal/modules/esm/translators.js#L190-L210 - -// Dynamically construct JS wrapper with custom static imports and named exports. -// Boots up an internal worker to resolve imports/exports through query from V8. - -static WASM_WRAP: &str = include_str!("./wasm_wrap.js"); - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -struct WasmModuleInfo { - import_list: Vec<String>, - export_list: Vec<String>, -} - -#[derive(Default)] -pub struct WasmCompiler { - cache: Arc<Mutex<HashMap<Url, CompiledModule>>>, -} - -impl WasmCompiler { - /// Create a new V8 worker with snapshot of WASM compiler and setup compiler's runtime. - fn setup_worker(global_state: GlobalState) -> CompilerWorker { - let entry_point = - ModuleSpecifier::resolve_url_or_path("./__$deno$wasm_compiler.ts") - .unwrap(); - let worker_state = - State::new(global_state.clone(), None, entry_point, DebugType::Internal) - .expect("Unable to create worker state"); - - // Count how many times we start the compiler worker. - global_state.compiler_starts.fetch_add(1, Ordering::SeqCst); - - let mut worker = CompilerWorker::new( - "WASM".to_string(), - startup_data::compiler_isolate_init(), - worker_state, - ); - worker.execute("bootstrap.wasmCompilerRuntime()").unwrap(); - worker - } - - pub async fn compile( - &self, - global_state: GlobalState, - source_file: &SourceFile, - ) -> Result<CompiledModule, ErrBox> { - let cache = self.cache.clone(); - let cache_ = self.cache.clone(); - let source_file = source_file.clone(); - - let maybe_cached = { cache.lock().unwrap().get(&source_file.url).cloned() }; - if let Some(m) = maybe_cached { - return Ok(m); - } - debug!(">>>>> wasm_compile START"); - let base64_data = base64::encode(&source_file.source_code); - let url = source_file.url.clone(); - let req_msg = serde_json::to_string(&base64_data) - .unwrap() - .into_boxed_str() - .into_boxed_bytes(); - let msg = execute_in_thread(global_state.clone(), req_msg).await?; - debug!("Received message from worker"); - let module_info: WasmModuleInfo = serde_json::from_slice(&msg).unwrap(); - debug!("WASM module info: {:#?}", &module_info); - let code = wrap_wasm_code( - &base64_data, - &module_info.import_list, - &module_info.export_list, - ); - debug!("Generated code: {}", &code); - let module = CompiledModule { - code, - name: url.to_string(), - }; - { - cache_.lock().unwrap().insert(url.clone(), module.clone()); - } - debug!("<<<<< wasm_compile END"); - Ok(module) - } -} - -async fn execute_in_thread( - global_state: GlobalState, - req: Buf, -) -> Result<Buf, ErrBox> { - let (handle_sender, handle_receiver) = - std::sync::mpsc::sync_channel::<Result<WebWorkerHandle, ErrBox>>(1); - let builder = - std::thread::Builder::new().name("deno-wasm-compiler".to_string()); - let join_handle = builder.spawn(move || { - let worker = WasmCompiler::setup_worker(global_state); - handle_sender.send(Ok(worker.thread_safe_handle())).unwrap(); - drop(handle_sender); - tokio_util::run_basic(worker).expect("Panic in event loop"); - })?; - let handle = handle_receiver.recv().unwrap()?; - handle.post_message(req)?; - let event = handle.get_event().await.expect("Compiler didn't respond"); - let buf = match event { - WorkerEvent::Message(buf) => Ok(buf), - WorkerEvent::Error(error) => Err(error), - WorkerEvent::TerminalError(error) => Err(error), - }?; - // Shutdown worker and wait for thread to finish - handle.terminate(); - join_handle.join().unwrap(); - Ok(buf) -} - -fn build_single_import(index: usize, origin: &str) -> String { - let origin_json = serde_json::to_string(origin).unwrap(); - format!( - r#"import * as m{} from {}; -importObject[{}] = m{}; -"#, - index, &origin_json, &origin_json, index - ) -} - -fn build_imports(imports: &[String]) -> String { - let mut code = String::from(""); - for (index, origin) in imports.iter().enumerate() { - code.push_str(&build_single_import(index, origin)); - } - code -} - -fn build_single_export(name: &str) -> String { - format!("export const {} = instance.exports.{};\n", name, name) -} - -fn build_exports(exports: &[String]) -> String { - let mut code = String::from(""); - for e in exports { - code.push_str(&build_single_export(e)); - } - code -} - -fn wrap_wasm_code( - base64_data: &str, - imports: &[String], - exports: &[String], -) -> String { - let imports_code = build_imports(imports); - let exports_code = build_exports(exports); - String::from(WASM_WRAP) - .replace("//IMPORTS\n", &imports_code) - .replace("//EXPORTS\n", &exports_code) - .replace("BASE64_DATA", base64_data) -} |