diff --git a/cli/global_state.rs b/cli/global_state.rs index a4b467edd3..590f97a769 100644 --- a/cli/global_state.rs +++ b/cli/global_state.rs @@ -216,7 +216,7 @@ impl GlobalState { if should_compile { self .ts_compiler - .compile(self, &out, target_lib, permissions, &module_graph, allow_js) + .compile(self, &out, target_lib, &module_graph, allow_js) .await?; } } diff --git a/cli/ops/compiler.rs b/cli/ops/compiler.rs deleted file mode 100644 index faf5fff327..0000000000 --- a/cli/ops/compiler.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -use deno_core::serde_json::json; -use std::sync::Arc; -use std::sync::Mutex; - -pub fn init( - rt: &mut deno_core::JsRuntime, - response: Arc>>, -) { - let custom_assets = std::collections::HashMap::new(); - // TODO(ry) use None. - // TODO(bartlomieju): is this op even required? - rt.register_op( - "op_fetch_asset", - crate::op_fetch_asset::op_fetch_asset(custom_assets), - ); - - super::reg_json_sync( - rt, - "op_compiler_respond", - move |_state, args, _bufs| { - let mut response_slot = response.lock().unwrap(); - let replaced_value = response_slot.replace(args.to_string()); - assert!( - replaced_value.is_none(), - "op_compiler_respond found unexpected existing compiler output", - ); - Ok(json!({})) - }, - ); -} diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index ddc648be6f..cbaa932aa1 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -3,7 +3,6 @@ mod dispatch_minimal; pub use dispatch_minimal::MinimalOp; -pub mod compiler; pub mod errors; pub mod fetch; pub mod fs; diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index b51cda95b6..91e638033e 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -80,12 +80,7 @@ async fn op_transpile( cli_state.check_unstable("Deno.transpile"); let args: TranspileArgs = serde_json::from_value(args)?; let global_state = cli_state.clone(); - let permissions = { - let state = state.borrow(); - state.borrow::().clone() - }; let result = - runtime_transpile(&global_state, permissions, &args.sources, &args.options) - .await?; + runtime_transpile(global_state, &args.sources, &args.options).await?; Ok(result) } diff --git a/cli/tests/020_json_modules.ts.out b/cli/tests/020_json_modules.ts.out index 54db523a01..8c07af2031 100644 --- a/cli/tests/020_json_modules.ts.out +++ b/cli/tests/020_json_modules.ts.out @@ -1,3 +1,3 @@ [WILDCARD] -error: Uncaught TypeError: Cannot resolve extension for "[WILDCARD]config.json" with mediaType "Json". +error: TypeError: Cannot resolve extension for "[WILDCARD]config.json" with mediaType "Json". [WILDCARD] \ No newline at end of file diff --git a/cli/tests/compiler_js_error.ts.out b/cli/tests/compiler_js_error.ts.out index 8c6e6e35eb..bb9d69610f 100644 --- a/cli/tests/compiler_js_error.ts.out +++ b/cli/tests/compiler_js_error.ts.out @@ -1,4 +1,4 @@ Check [WILDCARD]compiler_js_error.ts error: Uncaught Error: Error in TS compiler: -Uncaught AssertionError: Unexpected skip of the emit. +AssertionError: Unexpected skip of the emit. [WILDCARD] diff --git a/cli/tsc.rs b/cli/tsc.rs index b9a8c9c4c4..61d877e2dd 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -8,29 +8,26 @@ use crate::disk_cache::DiskCache; use crate::file_fetcher::SourceFile; use crate::file_fetcher::SourceFileFetcher; use crate::flags::Flags; -use crate::fmt_errors::JsError; use crate::global_state::GlobalState; use crate::js; use crate::media_type::MediaType; use crate::module_graph::ModuleGraph; use crate::module_graph::ModuleGraphLoader; -use crate::ops; use crate::permissions::Permissions; use crate::source_maps::SourceMapGetter; -use crate::state::CliModuleLoader; use crate::tsc_config; use crate::version; -use crate::worker::Worker; -use core::task::Context; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::futures::future::Future; -use deno_core::futures::future::FutureExt; +use deno_core::error::JsError; +use deno_core::json_op_sync; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::url::Url; +use deno_core::JsRuntime; use deno_core::ModuleSpecifier; +use deno_core::RuntimeOptions; use log::debug; use log::info; use log::Level; @@ -44,15 +41,12 @@ use std::collections::HashSet; use std::fs; use std::io; use std::ops::Deref; -use std::ops::DerefMut; use std::path::Path; use std::path::PathBuf; -use std::pin::Pin; use std::str; use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Mutex; -use std::task::Poll; use swc_common::comments::Comment; use swc_common::comments::CommentKind; use swc_ecmascript::dep_graph; @@ -125,71 +119,6 @@ pub struct CompiledModule { pub name: String, } -pub struct CompilerWorker { - worker: Worker, - response: Arc>>, -} - -impl CompilerWorker { - pub fn new( - name: String, - permissions: Permissions, - global_state: Arc, - ) -> Self { - let main_module = - ModuleSpecifier::resolve_url_or_path("./$deno$compiler.ts").unwrap(); - // TODO(bartlomieju): compiler worker shouldn't require any loader/state - let loader = CliModuleLoader::new(None); - let mut worker = Worker::new( - name, - Some(js::compiler_isolate_init()), - permissions, - main_module, - global_state, - loader, - false, - true, - ); - let response = Arc::new(Mutex::new(None)); - ops::runtime::init(&mut worker); - ops::errors::init(&mut worker); - ops::timers::init(&mut worker); - ops::compiler::init(&mut worker, response.clone()); - Self { worker, response } - } - - pub fn get_response(&mut self) -> String { - let mut maybe_response = self.response.lock().unwrap(); - assert!( - maybe_response.is_some(), - "Unexpected missing response from TS compiler" - ); - maybe_response.take().unwrap() - } -} - -impl Deref for CompilerWorker { - type Target = Worker; - fn deref(&self) -> &Self::Target { - &self.worker - } -} - -impl DerefMut for CompilerWorker { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.worker - } -} - -impl Future for CompilerWorker { - type Output = Result<(), AnyError>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - let inner = self.get_mut(); - inner.worker.poll_unpin(cx) - } -} - lazy_static! { /// Matches the `@deno-types` pragma. static ref DENO_TYPES_RE: Regex = @@ -224,24 +153,6 @@ fn warn_ignored_options( } } -/// Create a new worker with snapshot of TS compiler and setup compiler's -/// runtime. -fn create_compiler_worker( - global_state: &Arc, - permissions: Permissions, -) -> CompilerWorker { - // TODO(bartlomieju): this metric is never used anywhere - // Count how many times we start the compiler worker. - global_state.compiler_starts.fetch_add(1, Ordering::SeqCst); - - let mut worker = - CompilerWorker::new("TS".to_string(), permissions, global_state.clone()); - worker - .execute("globalThis.bootstrapCompilerRuntime()") - .unwrap(); - worker -} - #[derive(Clone)] pub enum TargetLib { Main, @@ -548,7 +459,6 @@ impl TsCompiler { global_state: &Arc, source_file: &SourceFile, target: TargetLib, - permissions: Permissions, module_graph: &ModuleGraph, allow_js: bool, ) -> Result<(), AnyError> { @@ -634,8 +544,7 @@ impl TsCompiler { let req_msg = j.to_string(); - let json_str = - execute_in_same_thread(global_state, permissions, req_msg).await?; + let json_str = execute_in_tsc(global_state.clone(), req_msg)?; let compile_response: CompileResponse = serde_json::from_str(&json_str)?; @@ -754,8 +663,7 @@ impl TsCompiler { let req_msg = j.to_string(); - let json_str = - execute_in_same_thread(global_state, permissions, req_msg).await?; + let json_str = execute_in_tsc(global_state.clone(), req_msg)?; let bundle_response: BundleResponse = serde_json::from_str(&json_str)?; @@ -1047,16 +955,62 @@ impl TsCompiler { } } -async fn execute_in_same_thread( - global_state: &Arc, - permissions: Permissions, +fn execute_in_tsc( + global_state: Arc, req: String, ) -> Result { - let mut worker = create_compiler_worker(&global_state, permissions); + // TODO(bartlomieju): this is only used in testing, I'm not sure it's + // worth keeping around + // Count how many times we start the compiler worker. + global_state.compiler_starts.fetch_add(1, Ordering::SeqCst); + + let mut js_runtime = JsRuntime::new(RuntimeOptions { + startup_snapshot: Some(js::compiler_isolate_init()), + ..Default::default() + }); + + let debug_flag = global_state + .flags + .log_level + .map_or(false, |l| l == log::Level::Debug); + let response = Arc::new(Mutex::new(None)); + + { + js_runtime.register_op( + "op_fetch_asset", + crate::op_fetch_asset::op_fetch_asset(HashMap::default()), + ); + let res = response.clone(); + js_runtime.register_op( + "op_compiler_respond", + json_op_sync(move |_state, args, _bufs| { + let mut response_slot = res.lock().unwrap(); + let replaced_value = response_slot.replace(args.to_string()); + assert!( + replaced_value.is_none(), + "op_compiler_respond found unexpected existing compiler output", + ); + Ok(json!({})) + }), + ); + } + + let bootstrap_script = format!( + "globalThis.bootstrapCompilerRuntime({{ debugFlag: {} }})", + debug_flag + ); + js_runtime.execute("", &bootstrap_script)?; + let script = format!("globalThis.tsCompilerOnMessage({{ data: {} }});", req); - worker.execute2("", &script)?; - (&mut *worker).await?; - Ok(worker.get_response()) + js_runtime.execute("", &script)?; + + let maybe_response = response.lock().unwrap().take(); + assert!( + maybe_response.is_some(), + "Unexpected missing response from TS compiler" + ); + + Ok(maybe_response.unwrap()) } async fn create_runtime_module_graph( @@ -1099,7 +1053,7 @@ async fn create_runtime_module_graph( Ok((root_names, module_graph_loader.get_graph())) } -fn js_error_to_errbox(error: AnyError) -> AnyError { +fn extract_js_error(error: AnyError) -> AnyError { match error.downcast::() { Ok(js_error) => { let msg = format!("Error in TS compiler:\n{}", js_error); @@ -1195,10 +1149,8 @@ pub async fn runtime_compile( let compiler = global_state.ts_compiler.clone(); - let json_str = execute_in_same_thread(global_state, permissions, req_msg) - .await - .map_err(js_error_to_errbox)?; - + let json_str = + execute_in_tsc(global_state.clone(), req_msg).map_err(extract_js_error)?; let response: RuntimeCompileResponse = serde_json::from_str(&json_str)?; if response.diagnostics.0.is_empty() && sources.is_none() { @@ -1304,9 +1256,8 @@ pub async fn runtime_bundle( }) .to_string(); - let json_str = execute_in_same_thread(global_state, permissions, req_msg) - .await - .map_err(js_error_to_errbox)?; + let json_str = + execute_in_tsc(global_state.clone(), req_msg).map_err(extract_js_error)?; let _response: RuntimeBundleResponse = serde_json::from_str(&json_str)?; // We're returning `Ok()` instead of `Err()` because it's not runtime // error if there were diagnostics produced; we want to let user handle @@ -1316,8 +1267,7 @@ pub async fn runtime_bundle( /// This function is used by `Deno.transpileOnly()` API. pub async fn runtime_transpile( - global_state: &Arc, - permissions: Permissions, + global_state: Arc, sources: &HashMap, maybe_options: &Option, ) -> Result { @@ -1343,9 +1293,8 @@ pub async fn runtime_transpile( }) .to_string(); - let json_str = execute_in_same_thread(global_state, permissions, req_msg) - .await - .map_err(js_error_to_errbox)?; + let json_str = + execute_in_tsc(global_state, req_msg).map_err(extract_js_error)?; let v = serde_json::from_str::(&json_str) .expect("Error decoding JSON string."); Ok(v) @@ -1628,14 +1577,7 @@ mod tests { .unwrap(); let result = ts_compiler - .compile( - &mock_state, - &out, - TargetLib::Main, - Permissions::allow_all(), - &module_graph, - false, - ) + .compile(&mock_state, &out, TargetLib::Main, &module_graph, false) .await; assert!(result.is_ok()); let compiled_file = ts_compiler.get_compiled_module(&out.url).unwrap(); diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index a6989381d1..5db73eda7a 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -106,11 +106,6 @@ delete Object.prototype.__proto__; }); } - function opNow() { - const res = core.jsonOpSync("op_now"); - return res.seconds * 1e3 + res.subsecNanos / 1e6; - } - // We really don't want to depend on JSON dispatch during snapshotting, so // this op exchanges strings with Rust as raw byte arrays. function getAsset(name) { @@ -728,7 +723,7 @@ delete Object.prototype.__proto__; function performanceStart() { stats.length = 0; // TODO(kitsonk) replace with performance.mark() when landed - statsStart = opNow(); + statsStart = new Date(); ts.performance.enable(); } @@ -765,7 +760,7 @@ delete Object.prototype.__proto__; function performanceEnd() { // TODO(kitsonk) replace with performance.measure() when landed - const duration = opNow() - statsStart; + const duration = new Date() - statsStart; stats.push({ key: "Compile time", value: duration }); return stats; } @@ -1283,14 +1278,14 @@ delete Object.prototype.__proto__; ); result[fileName] = { source, map }; } - return Promise.resolve(result); + return result; } function opCompilerRespond(msg) { core.jsonOpSync("op_compiler_respond", msg); } - async function tsCompilerOnMessage(msg) { + function tsCompilerOnMessage(msg) { const request = msg.data; switch (request.type) { case CompilerRequestType.Compile: { @@ -1314,7 +1309,7 @@ delete Object.prototype.__proto__; break; } case CompilerRequestType.RuntimeTranspile: { - const result = await runtimeTranspile(request); + const result = runtimeTranspile(request); opCompilerRespond(result); break; } @@ -1327,24 +1322,16 @@ delete Object.prototype.__proto__; } } - function runtimeStart(source) { - core.ops(); - // First we send an empty `Start` message to let the privileged side know we - // are ready. The response should be a `StartRes` message containing the CLI - // args and other info. - const s = core.jsonOpSync("op_start"); - setLogDebug(s.debugFlag, source); - return s; - } - let hasBootstrapped = false; - function bootstrapCompilerRuntime() { + function bootstrapCompilerRuntime({ debugFlag }) { if (hasBootstrapped) { throw new Error("Worker runtime already bootstrapped"); } hasBootstrapped = true; - runtimeStart("TS"); + delete globalThis.__bootstrap; + core.ops(); + setLogDebug(!!debugFlag, "TS"); } globalThis.bootstrapCompilerRuntime = bootstrapCompilerRuntime;