summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ansi.rs5
-rw-r--r--src/cli.rs90
-rw-r--r--src/compiler.rs17
-rw-r--r--src/isolate.rs799
-rw-r--r--src/isolate_init.rs2
-rw-r--r--src/isolate_state.rs110
-rw-r--r--src/js_errors.rs53
-rw-r--r--src/libdeno.rs192
-rw-r--r--src/main.rs56
-rw-r--r--src/modules.rs82
-rw-r--r--src/msg.fbs7
-rw-r--r--src/msg.rs5
-rw-r--r--src/ops.rs486
-rw-r--r--src/resources.rs42
-rw-r--r--src/tokio_util.rs36
-rw-r--r--src/workers.rs87
16 files changed, 726 insertions, 1343 deletions
diff --git a/src/ansi.rs b/src/ansi.rs
index f9cd39ac4..95b5e0694 100644
--- a/src/ansi.rs
+++ b/src/ansi.rs
@@ -3,7 +3,6 @@ use ansi_term::Color::Fixed;
use ansi_term::Color::Red;
use ansi_term::Style;
use regex::Regex;
-use std::borrow::Cow;
use std::env;
use std::fmt;
@@ -19,8 +18,8 @@ lazy_static! {
}
/// Helper function to strip ansi codes.
-#[allow(dead_code)]
-pub fn strip_ansi_codes(s: &str) -> Cow<str> {
+#[cfg(test)]
+pub fn strip_ansi_codes(s: &str) -> std::borrow::Cow<str> {
STRIP_ANSI_RE.replace_all(s, "")
}
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 000000000..d80587013
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,90 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use crate::errors::DenoResult;
+use crate::isolate_init::IsolateInit;
+use crate::isolate_state::IsolateState;
+use crate::ops;
+use crate::permissions::DenoPermissions;
+use deno_core::deno_buf;
+use deno_core::deno_mod;
+use deno_core::Behavior;
+use deno_core::Op;
+use std::sync::atomic::Ordering;
+use std::sync::Arc;
+
+// Buf represents a byte array returned from a "Op". The message might be empty
+// (which will be translated into a null object on the javascript side) or it is
+// a heap allocated opaque sequence of bytes. Usually a flatbuffer message.
+pub type Buf = Box<[u8]>;
+
+/// Implements deno_core::Behavior for the main Deno command-line.
+pub struct Cli {
+ init: IsolateInit,
+ pub state: Arc<IsolateState>,
+ pub permissions: Arc<DenoPermissions>, // TODO(ry) move to IsolateState
+}
+
+impl Cli {
+ pub fn new(
+ init: IsolateInit,
+ state: Arc<IsolateState>,
+ permissions: DenoPermissions,
+ ) -> Self {
+ Self {
+ init,
+ state,
+ permissions: Arc::new(permissions),
+ }
+ }
+
+ #[inline]
+ pub fn check_read(&self, filename: &str) -> DenoResult<()> {
+ self.permissions.check_read(filename)
+ }
+
+ #[inline]
+ pub fn check_write(&self, filename: &str) -> DenoResult<()> {
+ self.permissions.check_write(filename)
+ }
+
+ #[inline]
+ pub fn check_env(&self) -> DenoResult<()> {
+ self.permissions.check_env()
+ }
+
+ #[inline]
+ pub fn check_net(&self, filename: &str) -> DenoResult<()> {
+ self.permissions.check_net(filename)
+ }
+
+ #[inline]
+ pub fn check_run(&self) -> DenoResult<()> {
+ self.permissions.check_run()
+ }
+}
+
+impl Behavior for Cli {
+ fn startup_snapshot(&mut self) -> Option<deno_buf> {
+ self.init.snapshot.take()
+ }
+
+ fn resolve(&mut self, specifier: &str, referrer: deno_mod) -> deno_mod {
+ self
+ .state
+ .metrics
+ .resolve_count
+ .fetch_add(1, Ordering::Relaxed);
+ let mut modules = self.state.modules.lock().unwrap();
+ modules.resolve_cb(&self.state.dir, specifier, referrer)
+ }
+
+ fn dispatch(
+ &mut self,
+ control: &[u8],
+ zero_copy: deno_buf,
+ ) -> (bool, Box<Op>) {
+ ops::dispatch(self, control, zero_copy)
+ }
+}
diff --git a/src/compiler.rs b/src/compiler.rs
index dab166f47..9edae8cf9 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -1,18 +1,16 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-use crate::isolate::Buf;
-use crate::isolate::IsolateState;
+use crate::cli::Buf;
use crate::isolate_init;
+use crate::isolate_state::IsolateState;
use crate::msg;
use crate::permissions::{DenoPermissions, PermissionAccessor};
use crate::resources;
use crate::resources::Resource;
use crate::resources::ResourceId;
use crate::workers;
-
use futures::Future;
use serde_json;
use std::str;
-use std::sync::Arc;
use std::sync::Mutex;
lazy_static! {
@@ -48,7 +46,7 @@ impl ModuleMetaData {
}
}
-fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource {
+fn lazy_start(parent_state: &IsolateState) -> Resource {
let mut cell = C_RID.lock().unwrap();
let isolate_init = isolate_init::compiler_isolate_init();
let permissions = DenoPermissions {
@@ -57,10 +55,11 @@ fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource {
allow_net: PermissionAccessor::from(true),
..Default::default()
};
+
let rid = cell.get_or_insert_with(|| {
let resource = workers::spawn(
isolate_init,
- parent_state.clone(),
+ parent_state,
"compilerMain()".to_string(),
permissions,
);
@@ -79,7 +78,7 @@ fn req(specifier: &str, referrer: &str) -> Buf {
}
pub fn compile_sync(
- parent_state: &Arc<IsolateState>,
+ parent_state: &IsolateState,
specifier: &str,
referrer: &str,
module_meta_data: &ModuleMetaData,
@@ -92,7 +91,9 @@ pub fn compile_sync(
send_future.wait().unwrap();
let recv_future = resources::worker_recv_message(compiler.rid);
- let res_msg = recv_future.wait().unwrap().unwrap();
+ let result = recv_future.wait().unwrap();
+ assert!(result.is_some());
+ let res_msg = result.unwrap();
let res_json = std::str::from_utf8(&res_msg).unwrap();
match serde_json::from_str::<serde_json::Value>(res_json) {
diff --git a/src/isolate.rs b/src/isolate.rs
index 8a77777d2..7f3c0d919 100644
--- a/src/isolate.rs
+++ b/src/isolate.rs
@@ -1,353 +1,82 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-// Do not use FlatBuffers in this module.
-// TODO Currently this module uses Tokio, but it would be nice if they were
-// decoupled.
-
-#![allow(dead_code)]
-
+use crate::cli::Cli;
use crate::compiler::compile_sync;
use crate::compiler::ModuleMetaData;
-use crate::deno_dir;
use crate::errors::DenoError;
-use crate::errors::DenoResult;
use crate::errors::RustOrJsError;
-use crate::flags;
-use crate::global_timer::GlobalTimer;
-use crate::isolate_init::IsolateInit;
-use crate::js_errors::apply_source_map;
-use crate::libdeno;
-use crate::modules::Modules;
+use crate::isolate_state::IsolateState;
+use crate::js_errors;
use crate::msg;
-use crate::permissions::DenoPermissions;
-use crate::tokio_util;
+use deno_core;
+use deno_core::deno_mod;
use deno_core::JSError;
-use futures::sync::mpsc as async_mpsc;
+use futures::Async;
use futures::Future;
-use libc::c_char;
-use libc::c_void;
-use std;
-use std::cell::Cell;
-use std::cell::RefCell;
-use std::env;
-use std::ffi::CStr;
-use std::ffi::CString;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::mpsc;
use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::{Once, ONCE_INIT};
-use tokio;
-
-// Buf represents a byte array returned from a "Op".
-// The message might be empty (which will be translated into a null object on
-// the javascript side) or it is a heap allocated opaque sequence of bytes.
-// Usually a flatbuffer message.
-pub type Buf = Box<[u8]>;
-
-// JS promises in Deno map onto a specific Future
-// which yields either a DenoError or a byte array.
-pub type Op = dyn Future<Item = Buf, Error = DenoError> + Send;
-
-// Returns (is_sync, op)
-pub type Dispatch = fn(
- isolate: &Isolate,
- buf: libdeno::deno_buf,
- zero_copy_buf: libdeno::deno_buf,
-) -> (bool, Box<Op>);
-
-pub struct Isolate {
- libdeno_isolate: *const libdeno::isolate,
- dispatch: Dispatch,
- rx: mpsc::Receiver<(usize, Buf)>,
- tx: mpsc::Sender<(usize, Buf)>,
- ntasks: Cell<i32>,
- pub modules: RefCell<Modules>,
- pub state: Arc<IsolateState>,
- pub permissions: Arc<DenoPermissions>,
-}
-
-pub type WorkerSender = async_mpsc::Sender<Buf>;
-pub type WorkerReceiver = async_mpsc::Receiver<Buf>;
-pub type WorkerChannels = (WorkerSender, WorkerReceiver);
-
-// Isolate cannot be passed between threads but IsolateState can.
-// IsolateState satisfies Send and Sync.
-// So any state that needs to be accessed outside the main V8 thread should be
-// inside IsolateState.
-#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
-pub struct IsolateState {
- pub dir: deno_dir::DenoDir,
- pub argv: Vec<String>,
- pub flags: flags::DenoFlags,
- pub metrics: Metrics,
- pub worker_channels: Option<Mutex<WorkerChannels>>,
- pub global_timer: Mutex<GlobalTimer>,
-}
-
-impl IsolateState {
- pub fn new(
- flags: flags::DenoFlags,
- argv_rest: Vec<String>,
- worker_channels: Option<WorkerChannels>,
- ) -> Self {
- let custom_root = env::var("DENO_DIR").map(|s| s.into()).ok();
-
- Self {
- dir: deno_dir::DenoDir::new(flags.reload, flags.recompile, custom_root)
- .unwrap(),
- argv: argv_rest,
- flags,
- metrics: Metrics::default(),
- worker_channels: worker_channels.map(Mutex::new),
- global_timer: Mutex::new(GlobalTimer::new()),
- }
- }
- pub fn main_module(&self) -> Option<String> {
- if self.argv.len() <= 1 {
- None
- } else {
- let specifier = self.argv[1].clone();
- let referrer = ".";
- match self.dir.resolve_module_url(&specifier, referrer) {
- Ok(url) => Some(url.to_string()),
- Err(e) => {
- debug!("Potentially swallowed error {}", e);
- None
- }
- }
- }
- }
+type CoreIsolate = deno_core::Isolate<Cli>;
- #[cfg(test)]
- pub fn mock() -> Arc<IsolateState> {
- let argv = vec![String::from("./deno"), String::from("hello.js")];
- // For debugging: argv.push_back(String::from("-D"));
- let (flags, rest_argv, _) = flags::set_flags(argv).unwrap();
- Arc::new(IsolateState::new(flags, rest_argv, None))
- }
-
- fn metrics_op_dispatched(
- &self,
- bytes_sent_control: usize,
- bytes_sent_data: usize,
- ) {
- self.metrics.ops_dispatched.fetch_add(1, Ordering::SeqCst);
- self
- .metrics
- .bytes_sent_control
- .fetch_add(bytes_sent_control, Ordering::SeqCst);
- self
- .metrics
- .bytes_sent_data
- .fetch_add(bytes_sent_data, Ordering::SeqCst);
- }
-
- fn metrics_op_completed(&self, bytes_received: usize) {
- self.metrics.ops_completed.fetch_add(1, Ordering::SeqCst);
- self
- .metrics
- .bytes_received
- .fetch_add(bytes_received, Ordering::SeqCst);
- }
-}
-
-// AtomicU64 is currently unstable
-#[derive(Default)]
-pub struct Metrics {
- pub ops_dispatched: AtomicUsize,
- pub ops_completed: AtomicUsize,
- pub bytes_sent_control: AtomicUsize,
- pub bytes_sent_data: AtomicUsize,
- pub bytes_received: AtomicUsize,
- pub resolve_count: AtomicUsize,
+/// Wraps deno_core::Isolate to provide source maps, ops for the CLI, and
+/// high-level module loading
+pub struct Isolate {
+ inner: CoreIsolate,
+ state: Arc<IsolateState>,
}
-static DENO_INIT: Once = ONCE_INIT;
-
impl Isolate {
- pub fn new(
- init: IsolateInit,
- state: Arc<IsolateState>,
- dispatch: Dispatch,
- permissions: DenoPermissions,
- ) -> Self {
- DENO_INIT.call_once(|| {
- unsafe { libdeno::deno_init() };
- });
- let config = libdeno::deno_config {
- will_snapshot: 0,
- load_snapshot: match init.snapshot {
- Some(s) => s,
- None => libdeno::deno_buf::empty(),
- },
- shared: libdeno::deno_buf::empty(), // TODO Use for message passing.
- recv_cb: pre_dispatch,
- };
- let libdeno_isolate = unsafe { libdeno::deno_new(config) };
- // This channel handles sending async messages back to the runtime.
- let (tx, rx) = mpsc::channel::<(usize, Buf)>();
-
- let new_isolate = Self {
- libdeno_isolate,
- dispatch,
- rx,
- tx,
- ntasks: Cell::new(0),
- modules: RefCell::new(Modules::new()),
+ pub fn new(cli: Cli) -> Isolate {
+ let state = cli.state.clone();
+ Self {
+ inner: CoreIsolate::new(cli),
state,
- permissions: Arc::new(permissions),
- };
-
- // Run init script if present.
- match init.init_script {
- Some(init_script) => new_isolate
- .execute2(init_script.filename.as_str(), init_script.source.as_str())
- .unwrap(),
- None => {}
- };
-
- new_isolate
- }
-
- #[inline]
- pub fn as_raw_ptr(&self) -> *const c_void {
- self as *const _ as *const c_void
- }
-
- #[inline]
- pub unsafe fn from_raw_ptr<'a>(ptr: *const c_void) -> &'a Self {
- let ptr = ptr as *const _;
- &*ptr
- }
-
- #[inline]
- pub fn check_read(&self, filename: &str) -> DenoResult<()> {
- self.permissions.check_read(filename)
- }
-
- #[inline]
- pub fn check_write(&self, filename: &str) -> DenoResult<()> {
- self.permissions.check_write(filename)
- }
-
- #[inline]
- pub fn check_env(&self) -> DenoResult<()> {
- self.permissions.check_env()
- }
-
- #[inline]
- pub fn check_net(&self, filename: &str) -> DenoResult<()> {
- self.permissions.check_net(filename)
- }
-
- #[inline]
- pub fn check_run(&self) -> DenoResult<()> {
- self.permissions.check_run()
- }
-
- pub fn last_exception(&self) -> Option<JSError> {
- let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
- if ptr.is_null() {
- None
- } else {
- let cstr = unsafe { CStr::from_ptr(ptr) };
- let v8_exception = cstr.to_str().unwrap();
- debug!("v8_exception\n{}\n", v8_exception);
- let js_error = JSError::from_v8_exception(v8_exception).unwrap();
- let js_error_mapped = apply_source_map(&js_error, &self.state.dir);
- Some(js_error_mapped)
}
}
/// Same as execute2() but the filename defaults to "<anonymous>".
- pub fn execute(&self, js_source: &str) -> Result<(), JSError> {
+ pub fn execute(&mut self, js_source: &str) -> Result<(), JSError> {
self.execute2("<anonymous>", js_source)
}
/// Executes the provided JavaScript source code. The js_filename argument is
/// provided only for debugging purposes.
pub fn execute2(
- &self,
+ &mut self,
js_filename: &str,
js_source: &str,
) -> Result<(), JSError> {
- let filename = CString::new(js_filename).unwrap();
- let source = CString::new(js_source).unwrap();
- unsafe {
- libdeno::deno_execute(
- self.libdeno_isolate,
- self.as_raw_ptr(),
- filename.as_ptr(),
- source.as_ptr(),
- )
- };
- if let Some(err) = self.last_exception() {
- return Err(err);
- }
- Ok(())
- }
-
- pub fn mod_new(
- &mut self,
- main: bool,
- name: String,
- source: String,
- ) -> Result<libdeno::deno_mod, JSError> {
- let name_ = CString::new(name.clone()).unwrap();
- let name_ptr = name_.as_ptr() as *const c_char;
-
- let source_ = CString::new(source.clone()).unwrap();
- let source_ptr = source_.as_ptr() as *const c_char;
-
- let id = unsafe {
- libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr)
- };
- if let Some(js_error) = self.last_exception() {
- assert_eq!(id, 0);
- return Err(js_error);
- }
-
- self.modules.borrow_mut().register(id, &name);
-
- Ok(id)
+ self.inner.execute(js_filename, js_source)
}
// TODO(ry) make this return a future.
- pub fn mod_load_deps(
- &mut self,
- id: libdeno::deno_mod,
- ) -> Result<(), RustOrJsError> {
+ fn mod_load_deps(&self, id: deno_mod) -> Result<(), RustOrJsError> {
// basically iterate over the imports, start loading them.
- let referrer_name =
- { self.modules.borrow_mut().get_name(id).unwrap().clone() };
- let len =
- unsafe { libdeno::deno_mod_imports_len(self.libdeno_isolate, id) };
-
- for i in 0..len {
- let specifier_ptr =
- unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) };
- let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) };
- let specifier: &str = specifier_c.to_str().unwrap();
+ let referrer_name = {
+ let g = self.state.modules.lock().unwrap();
+ g.get_name(id).unwrap().clone()
+ };
+ for specifier in self.inner.mod_get_imports(id) {
let (name, _local_filename) = self
.state
.dir
- .resolve_module(specifier, &referrer_name)
+ .resolve_module(&specifier, &referrer_name)
.map_err(DenoError::from)
.map_err(RustOrJsError::from)?;
- debug!("mod_load_deps {} {}", i, name);
+ debug!("mod_load_deps {}", name);
- if !self.modules.borrow_mut().is_registered(&name) {
+ if !self.state.modules.lock().unwrap().is_registered(&name) {
let out = fetch_module_meta_data_and_maybe_compile(
&self.state,
- specifier,
+ &specifier,
&referrer_name,
)?;
- let child_id =
- self.mod_new(false, out.module_name.clone(), out.js_source())?;
+ let child_id = self.mod_new_and_register(
+ false,
+ &out.module_name.clone(),
+ &out.js_source(),
+ )?;
self.mod_load_deps(child_id)?;
}
@@ -356,140 +85,77 @@ impl Isolate {
Ok(())
}
- pub fn mod_instantiate(&self, id: libdeno::deno_mod) -> Result<(), JSError> {
- unsafe {
- libdeno::deno_mod_instantiate(
- self.libdeno_isolate,
- self.as_raw_ptr(),
- id,
- resolve_cb,
- )
- };
- if let Some(js_error) = self.last_exception() {
- return Err(js_error);
- }
-
- Ok(())
- }
-
- pub fn mod_evaluate(&self, id: libdeno::deno_mod) -> Result<(), JSError> {
- unsafe {
- libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id)
- };
- if let Some(js_error) = self.last_exception() {
- return Err(js_error);
- }
- Ok(())
- }
-
/// Executes the provided JavaScript module.
pub fn execute_mod(
&mut self,
js_filename: &str,
is_prefetch: bool,
) -> Result<(), RustOrJsError> {
- let out =
- fetch_module_meta_data_and_maybe_compile(&self.state, js_filename, ".")
- .map_err(RustOrJsError::from)?;
+ // TODO move isolate_state::execute_mod impl here.
+ self
+ .execute_mod_inner(js_filename, is_prefetch)
+ .map_err(|err| match err {
+ RustOrJsError::Js(err) => RustOrJsError::Js(self.apply_source_map(err)),
+ x => x,
+ })
+ }
+
+ /// High-level way to execute modules.
+ /// This will issue HTTP requests and file system calls.
+ /// Blocks. TODO(ry) Don't block.
+ fn execute_mod_inner(
+ &mut self,
+ url: &str,
+ is_prefetch: bool,
+ ) -> Result<(), RustOrJsError> {
+ let out = fetch_module_meta_data_and_maybe_compile(&self.state, url, ".")
+ .map_err(RustOrJsError::from)?;
let id = self
- .mod_new(true, out.module_name.clone(), out.js_source())
+ .mod_new_and_register(true, &out.module_name.clone(), &out.js_source())
.map_err(RustOrJsError::from)?;
self.mod_load_deps(id)?;
- self.mod_instantiate(id).map_err(RustOrJsError::from)?;
+ self
+ .inner
+ .mod_instantiate(id)
+ .map_err(RustOrJsError::from)?;
if !is_prefetch {
- self.mod_evaluate(id).map_err(RustOrJsError::from)?;
- }
- Ok(())
- }
-
- pub fn respond(&self, zero_copy_id: usize, buf: Buf) {
- self.state.metrics_op_completed(buf.len());
-
- // This will be cleaned up in the future.
- if zero_copy_id > 0 {
- unsafe {
- libdeno::deno_zero_copy_release(self.libdeno_isolate, zero_copy_id)
- }
- }
-
- // deno_respond will memcpy the buf into V8's heap,
- // so borrowing a reference here is sufficient.
- unsafe {
- libdeno::deno_respond(
- self.libdeno_isolate,
- self.as_raw_ptr(),
- buf.as_ref().into(),
- )
- }
- }
-
- fn complete_op(&self, zero_copy_id: usize, buf: Buf) {
- // Receiving a message on rx exactly corresponds to an async task
- // completing.
- self.ntasks_decrement();
- // Call into JS with the buf.
- self.respond(zero_copy_id, buf);
- }
-
- fn timeout(&self) {
- let dummy_buf = libdeno::deno_buf::empty();
- unsafe {
- libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), dummy_buf)
- }
- }
-
- fn check_promise_errors(&self) {
- unsafe {
- libdeno::deno_check_promise_errors(self.libdeno_isolate);
- }
- }
-
- // TODO Use Park abstraction? Note at time of writing Tokio default runtime
- // does not have new_with_park().
- pub fn event_loop(&self) -> Result<(), JSError> {
- // Main thread event loop.
- while !self.is_idle() {
- match self.rx.recv() {
- Ok((zero_copy_id, buf)) => self.complete_op(zero_copy_id, buf),
- Err(e) => panic!("Isolate.rx.recv() failed: {:?}", e),
- }
- self.check_promise_errors();
- if let Some(err) = self.last_exception() {
- return Err(err);
- }
- }
- // Check on done
- self.check_promise_errors();
- if let Some(err) = self.last_exception() {
- return Err(err);
+ self.inner.mod_evaluate(id).map_err(RustOrJsError::from)?;
}
Ok(())
}
- #[inline]
- fn ntasks_increment(&self) {
- assert!(self.ntasks.get() >= 0);
- self.ntasks.set(self.ntasks.get() + 1);
+ /// Wraps Isolate::mod_new but registers with modules.
+ fn mod_new_and_register(
+ &self,
+ main: bool,
+ name: &str,
+ source: &str,
+ ) -> Result<deno_mod, JSError> {
+ let id = self.inner.mod_new(main, name, source)?;
+ self.state.modules.lock().unwrap().register(id, &name);
+ Ok(id)
}
- #[inline]
- fn ntasks_decrement(&self) {
- self.ntasks.set(self.ntasks.get() - 1);
- assert!(self.ntasks.get() >= 0);
+ pub fn print_file_info(&self, module: &str) {
+ let m = self.state.modules.lock().unwrap();
+ m.print_file_info(&self.state.dir, module.to_string());
}
- #[inline]
- fn is_idle(&self) -> bool {
- self.ntasks.get() == 0
+ /// Applies source map to the error.
+ fn apply_source_map(&self, err: JSError) -> JSError {
+ js_errors::apply_source_map(&err, &self.state.dir)
}
}
-impl Drop for Isolate {
- fn drop(&mut self) {
- unsafe { libdeno::deno_delete(self.libdeno_isolate) }
+impl Future for Isolate {
+ type Item = ();
+ type Error = JSError;
+
+ fn poll(&mut self) -> Result<Async<()>, Self::Error> {
+ self.inner.poll().map_err(|err| self.apply_source_map(err))
}
}
@@ -511,308 +177,69 @@ fn fetch_module_meta_data_and_maybe_compile(
Ok(out)
}
-extern "C" fn resolve_cb(
- user_data: *mut c_void,
- specifier_ptr: *const c_char,
- referrer: libdeno::deno_mod,
-) -> libdeno::deno_mod {
- let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
- let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) };
- let specifier: &str = specifier_c.to_str().unwrap();
- isolate
- .state
- .metrics
- .resolve_count
- .fetch_add(1, Ordering::Relaxed);
- isolate.modules.borrow_mut().resolve_cb(
- &isolate.state.dir,
- specifier,
- referrer,
- )
-}
-
-// Dereferences the C pointer into the Rust Isolate object.
-extern "C" fn pre_dispatch(
- user_data: *mut c_void,
- control_buf: libdeno::deno_buf,
- zero_copy_buf: libdeno::deno_buf,
-) {
- // for metrics
- let bytes_sent_control = control_buf.len();
- let bytes_sent_zero_copy = zero_copy_buf.len();
-
- let zero_copy_id = zero_copy_buf.zero_copy_id;
-
- // We should ensure that there is no other `&mut Isolate` exists.
- // And also, it should be in the same thread with other `&Isolate`s.
- let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
- let dispatch = isolate.dispatch;
- let (is_sync, op) = dispatch(isolate, control_buf, zero_copy_buf);
-
- isolate
- .state
- .metrics_op_dispatched(bytes_sent_control, bytes_sent_zero_copy);
-
- if is_sync {
- // Execute op synchronously.
- let buf = tokio_util::block_on(op).unwrap();
- let buf_size = buf.len();
-
- if buf_size == 0 {
- // FIXME
- isolate.state.metrics_op_completed(buf.len());
- } else {
- // Set the synchronous response, the value returned from isolate.send().
- isolate.respond(zero_copy_id, buf);
- }
- } else {
- // Execute op asynchronously.
- let tx = isolate.tx.clone();
-
- // TODO Ideally Tokio would could tell us how many tasks are executing, but
- // it cannot currently. Therefore we track top-level promises/tasks
- // manually.
- isolate.ntasks_increment();
-
- let task = op
- .and_then(move |buf| {
- let sender = tx; // tx is moved to new thread
- sender.send((zero_copy_id, buf)).expect("tx.send error");
- Ok(())
- }).map_err(|_| ());
- tokio::spawn(task);
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
- use futures;
-
- #[test]
- fn test_dispatch_sync() {
- let state = IsolateState::mock();
- let init = IsolateInit {
- snapshot: None,
- init_script: None,
- };
- let isolate =
- Isolate::new(init, state, dispatch_sync, DenoPermissions::default());
- tokio_util::init(|| {
- isolate
- .execute(
- r#"
- const m = new Uint8Array([4, 5, 6]);
- let n = libdeno.send(m);
- if (!(n.byteLength === 3 &&
- n[0] === 1 &&
- n[1] === 2 &&
- n[2] === 3)) {
- throw Error("assert error");
- }
- "#,
- ).expect("execute error");
- isolate.event_loop().ok();
- });
- }
-
- fn dispatch_sync(
- _isolate: &Isolate,
- control: libdeno::deno_buf,
- data: libdeno::deno_buf,
- ) -> (bool, Box<Op>) {
- assert_eq!(control[0], 4);
- assert_eq!(control[1], 5);
- assert_eq!(control[2], 6);
- assert_eq!(data.len(), 0);
- // Send back some sync response.
- let vec: Vec<u8> = vec![1, 2, 3];
- let control = vec.into_boxed_slice();
- let op = Box::new(futures::future::ok(control));
- (true, op)
- }
-
- #[test]
- fn test_metrics_sync() {
- let state = IsolateState::mock();
- let init = IsolateInit {
- snapshot: None,
- init_script: None,
- };
- let isolate = Isolate::new(
- init,
- state,
- metrics_dispatch_sync,
- DenoPermissions::default(),
- );
- tokio_util::init(|| {
- // Verify that metrics have been properly initialized.
- {
- let metrics = &isolate.state.metrics;
- assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 0);
- }
-
- isolate
- .execute(
- r#"
- const control = new Uint8Array([4, 5, 6]);
- const data = new Uint8Array([42, 43, 44, 45, 46]);
- libdeno.send(control, data);
- "#,
- ).expect("execute error");;
- isolate.event_loop().unwrap();
- let metrics = &isolate.state.metrics;
- assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1);
- assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 1);
- assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3);
- assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5);
- assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 4);
- });
- }
-
- #[test]
- fn test_metrics_async() {
- let state = IsolateState::mock();
- let init = IsolateInit {
- snapshot: None,
- init_script: None,
- };
- let isolate = Isolate::new(
- init,
- state,
- metrics_dispatch_async,
- DenoPermissions::default(),
- );
- tokio_util::init(|| {
- // Verify that metrics have been properly initialized.
- {
- let metrics = &isolate.state.metrics;
- assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 0);
- assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 0);
- }
-
- isolate
- .execute(
- r#"
- const control = new Uint8Array([4, 5, 6]);
- const data = new Uint8Array([42, 43, 44, 45, 46]);
- let r = libdeno.send(control, data);
- libdeno.recv(() => {});
- if (r != null) throw Error("expected null");
- "#,
- ).expect("execute error");
-
- // Make sure relevant metrics are updated before task is executed.
- {
- let metrics = &isolate.state.metrics;
- assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1);
- assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3);
- assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5);
- // Note we cannot check ops_completed nor bytes_received because that
- // would be a race condition. It might be nice to have use a oneshot
- // with metrics_dispatch_async() to properly validate them.
- }
-
- isolate.event_loop().unwrap();
-
- // Make sure relevant metrics are updated after task is executed.
- {
- let metrics = &isolate.state.metrics;
- assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1);
- assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 1);
- assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3);
- assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5);
- assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 4);
- }
- });
- }
-
- fn metrics_dispatch_sync(
- _isolate: &Isolate,
- _control: libdeno::deno_buf,
- _data: libdeno::deno_buf,
- ) -> (bool, Box<Op>) {
- // Send back some sync response
- let vec: Box<[u8]> = vec![1, 2, 3, 4].into_boxed_slice();
- let op = Box::new(futures::future::ok(vec));
- (true, op)
- }
-
- fn metrics_dispatch_async(
- _isolate: &Isolate,
- _control: libdeno::deno_buf,
- _data: libdeno::deno_buf,
- ) -> (bool, Box<Op>) {
- // Send back some sync response
- let vec: Box<[u8]> = vec![1, 2, 3, 4].into_boxed_slice();
- let op = Box::new(futures::future::ok(vec));
- (false, op)
- }
-
- #[test]
- fn thread_safety() {
- fn is_thread_safe<T: Sync + Send>() {}
- is_thread_safe::<IsolateState>();
- }
+ use crate::flags;
+ use crate::isolate_init::IsolateInit;
+ use crate::permissions::DenoPermissions;
+ use crate::tokio_util;
+ use futures::future::lazy;
+ use std::sync::atomic::Ordering;
#[test]
fn execute_mod() {
let filename = std::env::current_dir()
.unwrap()
.join("tests/esm_imports_a.js");
- let filename = filename.to_str().unwrap();
+ let filename = filename.to_str().unwrap().to_string();
- let argv = vec![String::from("./deno"), String::from(filename)];
+ let argv = vec![String::from("./deno"), filename.clone()];
let (flags, rest_argv, _) = flags::set_flags(argv).unwrap();
let state = Arc::new(IsolateState::new(flags, rest_argv, None));
+ let state_ = state.clone();
let init = IsolateInit {
snapshot: None,
init_script: None,
};
- let mut isolate =
- Isolate::new(init, state, dispatch_sync, DenoPermissions::default());
- tokio_util::init(|| {
- isolate
- .execute_mod(filename, false)
- .expect("execute_mod error");
- isolate.event_loop().ok();
- });
-
- let metrics = &isolate.state.metrics;
+ tokio_util::run(lazy(move || {
+ let cli = Cli::new(init, state.clone(), DenoPermissions::default());
+ let mut isolate = Isolate::new(cli);
+ if let Err(err) = isolate.execute_mod(&filename, false) {
+ eprintln!("execute_mod err {:?}", err);
+ }
+ tokio_util::panic_on_error(isolate)
+ }));
+
+ let metrics = &state_.metrics;
assert_eq!(metrics.resolve_count.load(Ordering::SeqCst), 1);
}
#[test]
fn execute_mod_circular() {
let filename = std::env::current_dir().unwrap().join("tests/circular1.js");
- let filename = filename.to_str().unwrap();
+ let filename = filename.to_str().unwrap().to_string();
- let argv = vec![String::from("./deno"), String::from(filename)];
+ let argv = vec![String::from("./deno"), filename.clone()];
let (flags, rest_argv, _) = flags::set_flags(argv).unwrap();
let state = Arc::new(IsolateState::new(flags, rest_argv, None));
+ let state_ = state.clone();
let init = IsolateInit {
snapshot: None,
init_script: None,
};
- let mut isolate =
- Isolate::new(init, state, dispatch_sync, DenoPermissions::default());
- tokio_util::init(|| {
- isolate
- .execute_mod(filename, false)
- .expect("execute_mod error");
- isolate.event_loop().ok();
- });
-
- let metrics = &isolate.state.metrics;
+ tokio_util::run(lazy(move || {
+ let cli = Cli::new(init, state.clone(), DenoPermissions::default());
+ let mut isolate = Isolate::new(cli);
+ if let Err(err) = isolate.execute_mod(&filename, false) {
+ eprintln!("execute_mod err {:?}", err);
+ }
+ tokio_util::panic_on_error(isolate)
+ }));
+
+ let metrics = &state_.metrics;
assert_eq!(metrics.resolve_count.load(Ordering::SeqCst), 2);
}
}
diff --git a/src/isolate_init.rs b/src/isolate_init.rs
index 49fa0d96a..fbdfdd4a5 100644
--- a/src/isolate_init.rs
+++ b/src/isolate_init.rs
@@ -1,5 +1,5 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-use crate::libdeno::deno_buf;
+use deno_core::deno_buf;
pub struct IsolateInitScript {
pub source: String,
diff --git a/src/isolate_state.rs b/src/isolate_state.rs
new file mode 100644
index 000000000..4cc010389
--- /dev/null
+++ b/src/isolate_state.rs
@@ -0,0 +1,110 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+use crate::cli::Buf;
+use crate::deno_dir;
+use crate::flags;
+use crate::global_timer::GlobalTimer;
+use crate::modules::Modules;
+use futures::sync::mpsc as async_mpsc;
+use std;
+use std::env;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Mutex;
+
+pub type WorkerSender = async_mpsc::Sender<Buf>;
+pub type WorkerReceiver = async_mpsc::Receiver<Buf>;
+pub type WorkerChannels = (WorkerSender, WorkerReceiver);
+
+// AtomicU64 is currently unstable
+#[derive(Default)]
+pub struct Metrics {
+ pub ops_dispatched: AtomicUsize,
+ pub ops_completed: AtomicUsize,
+ pub bytes_sent_control: AtomicUsize,
+ pub bytes_sent_data: AtomicUsize,
+ pub bytes_received: AtomicUsize,
+ pub resolve_count: AtomicUsize,
+}
+
+// Isolate cannot be passed between threads but IsolateState can.
+// IsolateState satisfies Send and Sync.
+// So any state that needs to be accessed outside the main V8 thread should be
+// inside IsolateState.
+#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
+pub struct IsolateState {
+ pub dir: deno_dir::DenoDir,
+ pub argv: Vec<String>,
+ pub flags: flags::DenoFlags,
+ pub metrics: Metrics,
+ pub modules: Mutex<Modules>,
+ pub worker_channels: Option<Mutex<WorkerChannels>>,
+ pub global_timer: Mutex<GlobalTimer>,
+}
+
+impl IsolateState {
+ pub fn new(
+ flags: flags::DenoFlags,
+ argv_rest: Vec<String>,
+ worker_channels: Option<WorkerChannels>,
+ ) -> Self {
+ let custom_root = env::var("DENO_DIR").map(|s| s.into()).ok();
+
+ Self {
+ dir: deno_dir::DenoDir::new(flags.reload, flags.recompile, custom_root)
+ .unwrap(),
+ argv: argv_rest,
+ flags,
+ metrics: Metrics::default(),
+ modules: Mutex::new(Modules::new()),
+ worker_channels: worker_channels.map(Mutex::new),
+ global_timer: Mutex::new(GlobalTimer::new()),
+ }
+ }
+
+ pub fn main_module(&self) -> Option<String> {
+ if self.argv.len() <= 1 {
+ None
+ } else {
+ let specifier = self.argv[1].clone();
+ let referrer = ".";
+ match self.dir.resolve_module_url(&specifier, referrer) {
+ Ok(url) => Some(url.to_string()),
+ Err(e) => {
+ debug!("Potentially swallowed error {}", e);
+ None
+ }
+ }
+ }
+ }
+
+ #[cfg(test)]
+ pub fn mock() -> IsolateState {
+ let argv = vec![String::from("./deno"), String::from("hello.js")];
+ // For debugging: argv.push_back(String::from("-D"));
+ let (flags, rest_argv, _) = flags::set_flags(argv).unwrap();
+ IsolateState::new(flags, rest_argv, None)
+ }
+
+ pub fn metrics_op_dispatched(
+ &self,
+ bytes_sent_control: usize,
+ bytes_sent_data: usize,
+ ) {
+ self.metrics.ops_dispatched.fetch_add(1, Ordering::SeqCst);
+ self
+ .metrics
+ .bytes_sent_control
+ .fetch_add(bytes_sent_control, Ordering::SeqCst);
+ self
+ .metrics
+ .bytes_sent_data
+ .fetch_add(bytes_sent_data, Ordering::SeqCst);
+ }
+
+ pub fn metrics_op_completed(&self, bytes_received: usize) {
+ self.metrics.ops_completed.fetch_add(1, Ordering::SeqCst);
+ self
+ .metrics
+ .bytes_received
+ .fetch_add(bytes_received, Ordering::SeqCst);
+ }
+}
diff --git a/src/js_errors.rs b/src/js_errors.rs
index f42d9cb51..90c9f2007 100644
--- a/src/js_errors.rs
+++ b/src/js_errors.rs
@@ -206,36 +206,41 @@ pub fn apply_source_map(
}
}
-fn parse_map_string(
- script_name: &str,
- getter: &dyn SourceMapGetter,
-) -> Option<SourceMap> {
+// The bundle does not get built for 'cargo check', so we don't embed the
+// bundle source map.
+#[cfg(feature = "check-only")]
+fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> {
+ None
+}
+
+#[cfg(not(feature = "check-only"))]
+fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> {
match script_name {
- // The bundle does not get built for 'cargo check', so we don't embed the
- // bundle source map.
- #[cfg(not(feature = "check-only"))]
- "gen/bundle/main.js" => {
- let s =
- include_str!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/main.js.map"));
- SourceMap::from_json(s)
- }
- #[cfg(not(feature = "check-only"))]
- "gen/bundle/compiler.js" => {
- let s = include_str!(concat!(
+ "gen/bundle/main.js" => Some(
+ include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/main.js.map"))
+ .to_vec(),
+ ),
+ "gen/bundle/compiler.js" => Some(
+ include_bytes!(concat!(
env!("GN_OUT_DIR"),
"/gen/bundle/compiler.js.map"
- ));
- SourceMap::from_json(s)
- }
- _ => match getter.get_source_map(script_name) {
- None => None,
- Some(raw_source_map) => {
- SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap())
- }
- },
+ )).to_vec(),
+ ),
+ _ => None,
}
}
+fn parse_map_string(
+ script_name: &str,
+ getter: &dyn SourceMapGetter,
+) -> Option<SourceMap> {
+ builtin_source_map(script_name)
+ .or_else(|| getter.get_source_map(script_name))
+ .and_then(|raw_source_map| {
+ SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap())
+ })
+}
+
fn get_mappings<'a>(
script_name: &str,
mappings_map: &'a mut CachedMaps,
diff --git a/src/libdeno.rs b/src/libdeno.rs
deleted file mode 100644
index 6696a382b..000000000
--- a/src/libdeno.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-
-// TODO Remove. While core is being developed, it may not use the complete
-// libdeno API. Thus we allow dead code until things settle.
-#![allow(dead_code)]
-
-use libc::c_char;
-use libc::c_int;
-use libc::c_void;
-use libc::size_t;
-use std::ops::{Deref, DerefMut};
-use std::ptr::null;
-
-// TODO(F001): change this definition to `extern { pub type isolate; }`
-// After RFC 1861 is stablized. See https://github.com/rust-lang/rust/issues/43467.
-#[repr(C)]
-pub struct isolate {
- _unused: [u8; 0],
-}
-
-/// If "alloc_ptr" is not null, this type represents a buffer which is created
-/// in C side, and then passed to Rust side by `deno_recv_cb`. Finally it should
-/// be moved back to C side by `deno_respond`. If it is not passed to
-/// `deno_respond` in the end, it will be leaked.
-///
-/// If "alloc_ptr" is null, this type represents a borrowed slice.
-#[repr(C)]
-pub struct deno_buf {
- alloc_ptr: *const u8,
- alloc_len: usize,
- data_ptr: *const u8,
- data_len: usize,
- pub zero_copy_id: usize,
-}
-
-/// `deno_buf` can not clone, and there is no interior mutability.
-/// This type satisfies Send bound.
-unsafe impl Send for deno_buf {}
-
-impl deno_buf {
- #[inline]
- pub fn empty() -> Self {
- Self {
- alloc_ptr: null(),
- alloc_len: 0,
- data_ptr: null(),
- data_len: 0,
- zero_copy_id: 0,
- }
- }
-
- #[inline]
- pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self {
- Self {
- alloc_ptr: null(),
- alloc_len: 0,
- data_ptr: ptr,
- data_len: len,
- zero_copy_id: 0,
- }
- }
-}
-
-/// Converts Rust &Buf to libdeno `deno_buf`.
-impl<'a> From<&'a [u8]> for deno_buf {
- #[inline]
- fn from(x: &'a [u8]) -> Self {
- Self {
- alloc_ptr: null(),
- alloc_len: 0,
- data_ptr: x.as_ref().as_ptr(),
- data_len: x.len(),
- zero_copy_id: 0,
- }
- }
-}
-
-impl Deref for deno_buf {
- type Target = [u8];
- #[inline]
- fn deref(&self) -> &[u8] {
- unsafe { std::slice::from_raw_parts(self.data_ptr, self.data_len) }
- }
-}
-
-impl DerefMut for deno_buf {
- #[inline]
- fn deref_mut(&mut self) -> &mut [u8] {
- unsafe {
- if self.alloc_ptr.is_null() {
- panic!("Can't modify the buf");
- }
- std::slice::from_raw_parts_mut(self.data_ptr as *mut u8, self.data_len)
- }
- }
-}
-
-impl AsRef<[u8]> for deno_buf {
- #[inline]
- fn as_ref(&self) -> &[u8] {
- &*self
- }
-}
-
-impl AsMut<[u8]> for deno_buf {
- #[inline]
- fn as_mut(&mut self) -> &mut [u8] {
- if self.alloc_ptr.is_null() {
- panic!("Can't modify the buf");
- }
- &mut *self
- }
-}
-
-#[allow(non_camel_case_types)]
-type deno_recv_cb = unsafe extern "C" fn(
- user_data: *mut c_void,
- control_buf: deno_buf, // deprecated
- zero_copy_buf: deno_buf,
-);
-
-#[allow(non_camel_case_types)]
-pub type deno_mod = i32;
-
-#[allow(non_camel_case_types)]
-type deno_resolve_cb = unsafe extern "C" fn(
- user_data: *mut c_void,
- specifier: *const c_char,
- referrer: deno_mod,
-) -> deno_mod;
-
-#[repr(C)]
-pub struct deno_config {
- pub will_snapshot: c_int,
- pub load_snapshot: deno_buf,
- pub shared: deno_buf,
- pub recv_cb: deno_recv_cb,
-}
-
-extern "C" {
- pub fn deno_init();
- pub fn deno_v8_version() -> *const c_char;
- pub fn deno_set_v8_flags(argc: *mut c_int, argv: *mut *mut c_char);
- pub fn deno_new(config: deno_config) -> *const isolate;
- pub fn deno_delete(i: *const isolate);
- pub fn deno_last_exception(i: *const isolate) -> *const c_char;
- pub fn deno_check_promise_errors(i: *const isolate);
- pub fn deno_lock(i: *const isolate);
- pub fn deno_unlock(i: *const isolate);
- pub fn deno_respond(
- i: *const isolate,
- user_data: *const c_void,
- buf: deno_buf,
- );
- pub fn deno_zero_copy_release(i: *const isolate, zero_copy_id: usize);
- pub fn deno_execute(
- i: *const isolate,
- user_data: *const c_void,
- js_filename: *const c_char,
- js_source: *const c_char,
- );
-
- // Modules
-
- pub fn deno_mod_new(
- i: *const isolate,
- main: bool,
- name: *const c_char,
- source: *const c_char,
- ) -> deno_mod;
-
- pub fn deno_mod_imports_len(i: *const isolate, id: deno_mod) -> size_t;
-
- pub fn deno_mod_imports_get(
- i: *const isolate,
- id: deno_mod,
- index: size_t,
- ) -> *const c_char;
-
- pub fn deno_mod_instantiate(
- i: *const isolate,
- user_data: *const c_void,
- id: deno_mod,
- resolve_cb: deno_resolve_cb,
- );
-
- pub fn deno_mod_evaluate(
- i: *const isolate,
- user_data: *const c_void,
- id: deno_mod,
- );
-}
diff --git a/src/main.rs b/src/main.rs
index 7bafe5c3c..9afbbb8a9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,7 @@ extern crate futures;
extern crate serde_json;
mod ansi;
+pub mod cli;
pub mod compiler;
pub mod deno_dir;
pub mod errors;
@@ -19,8 +20,8 @@ mod http_body;
mod http_util;
pub mod isolate;
pub mod isolate_init;
+pub mod isolate_state;
pub mod js_errors;
-pub mod libdeno;
pub mod modules;
pub mod msg;
pub mod msg_util;
@@ -37,6 +38,12 @@ pub mod workers;
#[cfg(unix)]
mod eager_unix;
+use crate::cli::Cli;
+use crate::errors::RustOrJsError;
+use crate::isolate::Isolate;
+use crate::isolate_state::IsolateState;
+use futures::lazy;
+use futures::Future;
use log::{LevelFilter, Metadata, Record};
use std::env;
use std::sync::Arc;
@@ -58,11 +65,20 @@ impl log::Log for Logger {
fn flush(&self) {}
}
-fn print_err_and_exit(err: errors::RustOrJsError) {
+fn print_err_and_exit(err: RustOrJsError) {
eprintln!("{}", err.to_string());
std::process::exit(1);
}
+fn js_check<E>(r: Result<(), E>)
+where
+ E: Into<RustOrJsError>,
+{
+ if let Err(err) = r {
+ print_err_and_exit(err.into());
+ }
+}
+
fn main() {
#[cfg(windows)]
ansi_term::enable_ansi_support().ok(); // For Windows 10
@@ -95,39 +111,33 @@ fn main() {
let should_prefetch = flags.prefetch || flags.info;
let should_display_info = flags.info;
- let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None));
+ let state = Arc::new(IsolateState::new(flags, rest_argv, None));
+ let state_ = state.clone();
let isolate_init = isolate_init::deno_isolate_init();
let permissions = permissions::DenoPermissions::from_flags(&state.flags);
- let mut isolate =
- isolate::Isolate::new(isolate_init, state, ops::dispatch, permissions);
+ let cli = Cli::new(isolate_init, state_, permissions);
+ let mut isolate = Isolate::new(cli);
- tokio_util::init(|| {
+ let main_future = lazy(move || {
// Setup runtime.
- isolate
- .execute("denoMain();")
- .map_err(errors::RustOrJsError::from)
- .unwrap_or_else(print_err_and_exit);
+ js_check(isolate.execute("denoMain()"));
// Execute main module.
- if let Some(main_module) = isolate.state.main_module() {
+ if let Some(main_module) = state.main_module() {
debug!("main_module {}", main_module);
- isolate
- .execute_mod(&main_module, should_prefetch)
- .unwrap_or_else(print_err_and_exit);
+ js_check(isolate.execute_mod(&main_module, should_prefetch));
if should_display_info {
// Display file info and exit. Do not run file
- modules::print_file_info(
- &isolate.modules.borrow(),
- &isolate.state.dir,
- main_module,
- );
+ isolate.print_file_info(&main_module);
std::process::exit(0);
}
}
- isolate
- .event_loop()
- .map_err(errors::RustOrJsError::from)
- .unwrap_or_else(print_err_and_exit);
+ isolate.then(|result| {
+ js_check(result);
+ Ok(())
+ })
});
+
+ tokio_util::run(main_future);
}
diff --git a/src/modules.rs b/src/modules.rs
index 67be47dd4..908c31b6d 100644
--- a/src/modules.rs
+++ b/src/modules.rs
@@ -1,8 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::ansi;
use crate::deno_dir::DenoDir;
-use crate::libdeno::deno_mod;
use crate::msg;
+use deno_core::deno_mod;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt;
@@ -86,6 +86,44 @@ impl Modules {
return 0;
}
}
+
+ pub fn print_file_info(&self, deno_dir: &DenoDir, filename: String) {
+ let maybe_out = deno_dir.fetch_module_meta_data(&filename, ".");
+ if maybe_out.is_err() {
+ println!("{}", maybe_out.unwrap_err());
+ return;
+ }
+ let out = maybe_out.unwrap();
+
+ println!("{} {}", ansi::bold("local:".to_string()), &(out.filename));
+ println!(
+ "{} {}",
+ ansi::bold("type:".to_string()),
+ msg::enum_name_media_type(out.media_type)
+ );
+ if out.maybe_output_code_filename.is_some() {
+ println!(
+ "{} {}",
+ ansi::bold("compiled:".to_string()),
+ out.maybe_output_code_filename.as_ref().unwrap(),
+ );
+ }
+ if out.maybe_source_map_filename.is_some() {
+ println!(
+ "{} {}",
+ ansi::bold("map:".to_string()),
+ out.maybe_source_map_filename.as_ref().unwrap()
+ );
+ }
+
+ let deps = Deps::new(self, &out.module_name);
+ println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name);
+ if let Some(ref depsdeps) = deps.deps {
+ for d in depsdeps {
+ println!("{}", d);
+ }
+ }
+ }
}
pub struct Deps {
@@ -164,45 +202,3 @@ impl fmt::Display for Deps {
Ok(())
}
}
-
-pub fn print_file_info(
- modules: &Modules,
- deno_dir: &DenoDir,
- filename: String,
-) {
- let maybe_out = deno_dir.fetch_module_meta_data(&filename, ".");
- if maybe_out.is_err() {
- println!("{}", maybe_out.unwrap_err());
- return;
- }
- let out = maybe_out.unwrap();
-
- println!("{} {}", ansi::bold("local:".to_string()), &(out.filename));
- println!(
- "{} {}",
- ansi::bold("type:".to_string()),
- msg::enum_name_media_type(out.media_type)
- );
- if out.maybe_output_code_filename.is_some() {
- println!(
- "{} {}",
- ansi::bold("compiled:".to_string()),
- out.maybe_output_code_filename.as_ref().unwrap(),
- );
- }
- if out.maybe_source_map_filename.is_some() {
- println!(
- "{} {}",
- ansi::bold("map:".to_string()),
- out.maybe_source_map_filename.as_ref().unwrap()
- );
- }
-
- let deps = Deps::new(modules, &out.module_name);
- println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name);
- if let Some(ref depsdeps) = deps.deps {
- for d in depsdeps {
- println!("{}", d);
- }
- }
-}
diff --git a/src/msg.fbs b/src/msg.fbs
index 279264a45..243034cfb 100644
--- a/src/msg.fbs
+++ b/src/msg.fbs
@@ -139,13 +139,6 @@ enum MediaType: byte {
Unknown
}
-table Shared {
- lock: bool;
- head: int;
- tail: int;
- ring: [Base];
-}
-
table Base {
cmd_id: uint32;
sync: bool = false;
diff --git a/src/msg.rs b/src/msg.rs
index 74027d3d6..080f39de8 100644
--- a/src/msg.rs
+++ b/src/msg.rs
@@ -5,6 +5,7 @@
feature = "cargo-clippy",
allow(clippy::all, clippy::pedantic)
)]
+use crate::isolate_state;
use flatbuffers;
use std::sync::atomic::Ordering;
@@ -12,8 +13,8 @@ use std::sync::atomic::Ordering;
// build_extra/rust/run.py (for the GN+Ninja build).
include!(concat!(env!("GN_OUT_DIR"), "/gen/msg_generated.rs"));
-impl<'a> From<&'a super::isolate::Metrics> for MetricsResArgs {
- fn from(m: &'a super::isolate::Metrics) -> Self {
+impl<'a> From<&'a isolate_state::Metrics> for MetricsResArgs {
+ fn from(m: &'a isolate_state::Metrics) -> Self {
MetricsResArgs {
ops_dispatched: m.ops_dispatched.load(Ordering::SeqCst) as u64,
ops_completed: m.ops_completed.load(Ordering::SeqCst) as u64,
diff --git a/src/ops.rs b/src/ops.rs
index 495540b22..33a7d7cdd 100644
--- a/src/ops.rs
+++ b/src/ops.rs
@@ -1,18 +1,15 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-
use atty;
use crate::ansi;
+use crate::cli::Buf;
+use crate::cli::Cli;
use crate::errors;
use crate::errors::{permission_denied, DenoError, DenoResult, ErrorKind};
use crate::fs as deno_fs;
use crate::http_util;
-use crate::isolate::Buf;
-use crate::isolate::Isolate;
-use crate::isolate::IsolateState;
-use crate::isolate::Op;
+use crate::isolate_state::IsolateState;
use crate::js_errors::apply_source_map;
use crate::js_errors::JSErrorColor;
-use crate::libdeno;
use crate::msg;
use crate::msg_util;
use crate::repl;
@@ -22,7 +19,9 @@ use crate::resources::table_entries;
use crate::resources::Resource;
use crate::tokio_util;
use crate::version;
+use deno_core::deno_buf;
use deno_core::JSError;
+use deno_core::Op;
use flatbuffers::FlatBufferBuilder;
use futures;
use futures::Async;
@@ -54,11 +53,12 @@ use std::os::unix::process::ExitStatusExt;
type OpResult = DenoResult<Buf>;
-// TODO Ideally we wouldn't have to box the Op being returned.
+pub type OpWithError = dyn Future<Item = Buf, Error = DenoError> + Send;
+
+// TODO Ideally we wouldn't have to box the OpWithError being returned.
// The box is just to make it easier to get a prototype refactor working.
type OpCreator =
- fn(isolate: &Isolate, base: &msg::Base<'_>, data: libdeno::deno_buf)
- -> Box<Op>;
+ fn(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError>;
#[inline]
fn empty_buf() -> Buf {
@@ -70,16 +70,18 @@ fn empty_buf() -> Buf {
/// control corresponds to the first argument of libdeno.send().
/// data corresponds to the second argument of libdeno.send().
pub fn dispatch(
- isolate: &Isolate,
- control: libdeno::deno_buf,
- data: libdeno::deno_buf,
+ cli: &Cli,
+ control: &[u8],
+ zero_copy: deno_buf,
) -> (bool, Box<Op>) {
+ let bytes_sent_control = control.len();
+ let bytes_sent_zero_copy = zero_copy.len();
let base = msg::get_root_as_base(&control);
let is_sync = base.sync();
let inner_type = base.inner_type();
let cmd_id = base.cmd_id();
- let op: Box<Op> = {
+ let op: Box<OpWithError> = {
// Handle regular ops.
let op_creator: OpCreator = match inner_type {
msg::Any::Accept => op_accept,
@@ -132,11 +134,16 @@ pub fn dispatch(
msg::enum_name_any(inner_type)
)),
};
- op_creator(&isolate, &base, data)
+ op_creator(&cli, &base, zero_copy)
};
+ cli
+ .state
+ .metrics_op_dispatched(bytes_sent_control, bytes_sent_zero_copy);
+ let state = cli.state.clone();
+
let boxed_op = Box::new(
- op.or_else(move |err: DenoError| -> DenoResult<Buf> {
+ op.or_else(move |err: DenoError| -> Result<Buf, ()> {
debug!("op err {}", err);
// No matter whether we got an Err or Ok, we want a serialized message to
// send back. So transform the DenoError into a deno_buf.
@@ -151,7 +158,7 @@ pub fn dispatch(
..Default::default()
},
))
- }).and_then(move |buf: Buf| -> DenoResult<Buf> {
+ }).and_then(move |buf: Buf| -> Result<Buf, ()> {
// Handle empty responses. For sync responses we just want
// to send null. For async we want to send a small message
// with the cmd_id.
@@ -167,8 +174,9 @@ pub fn dispatch(
},
)
};
+ state.metrics_op_completed(buf.len());
Ok(buf)
- }),
+ }).map_err(|err| panic!("unexpected error {:?}", err)),
);
debug!(
@@ -180,10 +188,10 @@ pub fn dispatch(
}
fn op_now(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let start = SystemTime::now();
let since_the_epoch = start.duration_since(UNIX_EPOCH).unwrap();
@@ -204,10 +212,10 @@ fn op_now(
}
fn op_is_tty(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- _data: libdeno::deno_buf,
-) -> Box<Op> {
+ _data: deno_buf,
+) -> Box<OpWithError> {
let builder = &mut FlatBufferBuilder::new();
let inner = msg::IsTTYRes::create(
builder,
@@ -229,23 +237,23 @@ fn op_is_tty(
}
fn op_exit(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- _data: libdeno::deno_buf,
-) -> Box<Op> {
+ _data: deno_buf,
+) -> Box<OpWithError> {
let inner = base.inner_as_exit().unwrap();
std::process::exit(inner.code())
}
fn op_start(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let mut builder = FlatBufferBuilder::new();
- let argv = isolate
+ let argv = cli
.state
.argv
.iter()
@@ -266,10 +274,7 @@ fn op_start(
let deno_version = version::DENO;
let deno_version_off = builder.create_string(deno_version);
- let main_module = isolate
- .state
- .main_module()
- .map(|m| builder.create_string(&m));
+ let main_module = cli.state.main_module().map(|m| builder.create_string(&m));
let inner = msg::StartRes::create(
&mut builder,
@@ -278,9 +283,9 @@ fn op_start(
pid: std::process::id(),
argv: Some(argv_off),
main_module,
- debug_flag: isolate.state.flags.log_debug,
- types_flag: isolate.state.flags.types,
- version_flag: isolate.state.flags.version,
+ debug_flag: cli.state.flags.log_debug,
+ types_flag: cli.state.flags.types,
+ version_flag: cli.state.flags.version,
v8_version: Some(v8_version_off),
deno_version: Some(deno_version_off),
no_color: !ansi::use_color(),
@@ -301,16 +306,16 @@ fn op_start(
}
fn op_format_error(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_format_error().unwrap();
let orig_error = String::from(inner.error().unwrap());
let js_error = JSError::from_v8_exception(&orig_error).unwrap();
- let js_error_mapped = apply_source_map(&js_error, &isolate.state.dir);
+ let js_error_mapped = apply_source_map(&js_error, &cli.state.dir);
let js_error_string = JSErrorColor(&js_error_mapped).to_string();
let mut builder = FlatBufferBuilder::new();
@@ -349,22 +354,22 @@ fn serialize_response(
}
#[inline]
-pub fn ok_future(buf: Buf) -> Box<Op> {
+pub fn ok_future(buf: Buf) -> Box<OpWithError> {
Box::new(futures::future::ok(buf))
}
// Shout out to Earl Sweatshirt.
#[inline]
-pub fn odd_future(err: DenoError) -> Box<Op> {
+pub fn odd_future(err: DenoError) -> Box<OpWithError> {
Box::new(futures::future::err(err))
}
// https://github.com/denoland/deno/blob/golang/os.go#L100-L154
fn op_fetch_module_meta_data(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_fetch_module_meta_data().unwrap();
let cmd_id = base.cmd_id();
@@ -372,35 +377,32 @@ fn op_fetch_module_meta_data(
let referrer = inner.referrer().unwrap();
// Check for allow read since this operation could be used to read from the file system.
- if !isolate.permissions.allows_read() {
+ if !cli.permissions.allows_read() {
debug!("No read permission for fetch_module_meta_data");
return odd_future(permission_denied());
}
// Check for allow write since this operation could be used to write to the file system.
- if !isolate.permissions.allows_write() {
+ if !cli.permissions.allows_write() {
debug!("No network permission for fetch_module_meta_data");
return odd_future(permission_denied());
}
// Check for allow net since this operation could be used to make https/http requests.
- if !isolate.permissions.allows_net() {
+ if !cli.permissions.allows_net() {
debug!("No network permission for fetch_module_meta_data");
return odd_future(permission_denied());
}
assert_eq!(
- isolate.state.dir.root.join("gen"),
- isolate.state.dir.gen,
+ cli.state.dir.root.join("gen"),
+ cli.state.dir.gen,
"Sanity check"
);
Box::new(futures::future::result(|| -> OpResult {
let builder = &mut FlatBufferBuilder::new();
- let out = isolate
- .state
- .dir
- .fetch_module_meta_data(specifier, referrer)?;
+ let out = cli.state.dir.fetch_module_meta_data(specifier, referrer)?;
let data_off = builder.create_vector(out.source_code.as_slice());
let msg_args = msg::FetchModuleMetaDataResArgs {
module_name: Some(builder.create_string(&out.module_name)),
@@ -422,10 +424,10 @@ fn op_fetch_module_meta_data(
}
fn op_chdir(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_chdir().unwrap();
let directory = inner.directory().unwrap();
@@ -436,22 +438,22 @@ fn op_chdir(
}
fn op_global_timer_stop(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert!(base.sync());
assert_eq!(data.len(), 0);
- let mut t = isolate.state.global_timer.lock().unwrap();
+ let mut t = cli.state.global_timer.lock().unwrap();
t.cancel();
ok_future(empty_buf())
}
fn op_global_timer(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert!(!base.sync());
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
@@ -459,7 +461,7 @@ fn op_global_timer(
let val = inner.timeout();
assert!(val >= 0);
- let mut t = isolate.state.global_timer.lock().unwrap();
+ let mut t = cli.state.global_timer.lock().unwrap();
let deadline = Instant::now() + Duration::from_millis(val as u64);
let f = t.new_timeout(deadline);
@@ -480,30 +482,26 @@ fn op_global_timer(
}
fn op_set_env(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_set_env().unwrap();
let key = inner.key().unwrap();
let value = inner.value().unwrap();
- if let Err(e) = isolate.check_env() {
+ if let Err(e) = cli.check_env() {
return odd_future(e);
}
std::env::set_var(key, value);
ok_future(empty_buf())
}
-fn op_env(
- isolate: &Isolate,
- base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+fn op_env(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
- if let Err(e) = isolate.check_env() {
+ if let Err(e) = cli.check_env() {
return odd_future(e);
}
@@ -528,21 +526,21 @@ fn op_env(
}
fn op_permissions(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let builder = &mut FlatBufferBuilder::new();
let inner = msg::PermissionsRes::create(
builder,
&msg::PermissionsResArgs {
- run: isolate.permissions.allows_run(),
- read: isolate.permissions.allows_read(),
- write: isolate.permissions.allows_write(),
- net: isolate.permissions.allows_net(),
- env: isolate.permissions.allows_env(),
+ run: cli.permissions.allows_run(),
+ read: cli.permissions.allows_read(),
+ write: cli.permissions.allows_write(),
+ net: cli.permissions.allows_net(),
+ env: cli.permissions.allows_env(),
},
);
ok_future(serialize_response(
@@ -557,19 +555,19 @@ fn op_permissions(
}
fn op_revoke_permission(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_permission_revoke().unwrap();
let permission = inner.permission().unwrap();
let result = match permission {
- "run" => isolate.permissions.revoke_run(),
- "read" => isolate.permissions.revoke_read(),
- "write" => isolate.permissions.revoke_write(),
- "net" => isolate.permissions.revoke_net(),
- "env" => isolate.permissions.revoke_env(),
+ "run" => cli.permissions.revoke_run(),
+ "read" => cli.permissions.revoke_read(),
+ "write" => cli.permissions.revoke_write(),
+ "net" => cli.permissions.revoke_net(),
+ "env" => cli.permissions.revoke_env(),
_ => Ok(()),
};
if let Err(e) = result {
@@ -579,10 +577,10 @@ fn op_revoke_permission(
}
fn op_fetch(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
let inner = base.inner_as_fetch().unwrap();
let cmd_id = base.cmd_id();
@@ -602,7 +600,7 @@ fn op_fetch(
}
let req = maybe_req.unwrap();
- if let Err(e) = isolate.check_net(url) {
+ if let Err(e) = cli.check_net(url) {
return odd_future(e);
}
@@ -650,11 +648,11 @@ where
Ok(Ready(Ok(v))) => Ok(v.into()),
Ok(Ready(Err(err))) => Err(err),
Ok(NotReady) => Ok(NotReady),
- Err(_err) => panic!("blocking error"),
+ Err(err) => panic!("blocking error {}", err),
}
}
-fn blocking<F>(is_sync: bool, f: F) -> Box<Op>
+fn blocking<F>(is_sync: bool, f: F) -> Box<OpWithError>
where
F: 'static + Send + FnOnce() -> DenoResult<Buf>,
{
@@ -666,17 +664,17 @@ where
}
fn op_make_temp_dir(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let base = Box::new(*base);
let inner = base.inner_as_make_temp_dir().unwrap();
let cmd_id = base.cmd_id();
// FIXME
- if let Err(e) = isolate.check_write("make_temp") {
+ if let Err(e) = cli.check_write("make_temp") {
return odd_future(e);
}
@@ -715,17 +713,17 @@ fn op_make_temp_dir(
}
fn op_mkdir(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_mkdir().unwrap();
let path = String::from(inner.path().unwrap());
let recursive = inner.recursive();
let mode = inner.mode();
- if let Err(e) = isolate.check_write(&path) {
+ if let Err(e) = cli.check_write(&path) {
return odd_future(e);
}
@@ -737,16 +735,16 @@ fn op_mkdir(
}
fn op_chmod(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_chmod().unwrap();
let _mode = inner.mode();
let path = String::from(inner.path().unwrap());
- if let Err(e) = isolate.check_write(&path) {
+ if let Err(e) = cli.check_write(&path) {
return odd_future(e);
}
@@ -776,10 +774,10 @@ fn op_chmod(
}
fn op_open(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let inner = base.inner_as_open().unwrap();
@@ -825,20 +823,20 @@ fn op_open(
match mode {
"r" => {
- if let Err(e) = isolate.check_read(&filename_str) {
+ if let Err(e) = cli.check_read(&filename_str) {
return odd_future(e);
}
}
"w" | "a" | "x" => {
- if let Err(e) = isolate.check_write(&filename_str) {
+ if let Err(e) = cli.check_write(&filename_str) {
return odd_future(e);
}
}
&_ => {
- if let Err(e) = isolate.check_read(&filename_str) {
+ if let Err(e) = cli.check_read(&filename_str) {
return odd_future(e);
}
- if let Err(e) = isolate.check_write(&filename_str) {
+ if let Err(e) = cli.check_write(&filename_str) {
return odd_future(e);
}
}
@@ -866,10 +864,10 @@ fn op_open(
}
fn op_close(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_close().unwrap();
let rid = inner.rid();
@@ -883,10 +881,10 @@ fn op_close(
}
fn op_shutdown(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_shutdown().unwrap();
let rid = inner.rid();
@@ -909,10 +907,10 @@ fn op_shutdown(
}
fn op_read(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
let cmd_id = base.cmd_id();
let inner = base.inner_as_read().unwrap();
let rid = inner.rid();
@@ -947,10 +945,10 @@ fn op_read(
}
fn op_write(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
let cmd_id = base.cmd_id();
let inner = base.inner_as_write().unwrap();
let rid = inner.rid();
@@ -984,10 +982,10 @@ fn op_write(
}
fn op_seek(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let _cmd_id = base.cmd_id();
let inner = base.inner_as_seek().unwrap();
@@ -1006,17 +1004,17 @@ fn op_seek(
}
fn op_remove(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_remove().unwrap();
let path_ = inner.path().unwrap();
let path = PathBuf::from(path_);
let recursive = inner.recursive();
- if let Err(e) = isolate.check_write(path.to_str().unwrap()) {
+ if let Err(e) = cli.check_write(path.to_str().unwrap()) {
return odd_future(e);
}
@@ -1036,17 +1034,17 @@ fn op_remove(
// Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184
fn op_read_file(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_read_file().unwrap();
let cmd_id = base.cmd_id();
let filename_ = inner.filename().unwrap();
let filename = PathBuf::from(filename_);
debug!("op_read_file {}", filename.display());
- if let Err(e) = isolate.check_read(&filename_) {
+ if let Err(e) = cli.check_read(&filename_) {
return odd_future(e);
}
blocking(base.sync(), move || {
@@ -1074,10 +1072,10 @@ fn op_read_file(
}
fn op_copy_file(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_copy_file().unwrap();
let from_ = inner.from().unwrap();
@@ -1085,10 +1083,10 @@ fn op_copy_file(
let to_ = inner.to().unwrap();
let to = PathBuf::from(to_);
- if let Err(e) = isolate.check_read(&from_) {
+ if let Err(e) = cli.check_read(&from_) {
return odd_future(e);
}
- if let Err(e) = isolate.check_write(&to_) {
+ if let Err(e) = cli.check_write(&to_) {
return odd_future(e);
}
@@ -1130,10 +1128,10 @@ fn get_mode(_perm: &fs::Permissions) -> u32 {
}
fn op_cwd(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
Box::new(futures::future::result(|| -> OpResult {
@@ -1156,10 +1154,10 @@ fn op_cwd(
}
fn op_stat(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_stat().unwrap();
let cmd_id = base.cmd_id();
@@ -1167,7 +1165,7 @@ fn op_stat(
let filename = PathBuf::from(filename_);
let lstat = inner.lstat();
- if let Err(e) = isolate.check_read(&filename_) {
+ if let Err(e) = cli.check_read(&filename_) {
return odd_future(e);
}
@@ -1208,16 +1206,16 @@ fn op_stat(
}
fn op_read_dir(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_read_dir().unwrap();
let cmd_id = base.cmd_id();
let path = String::from(inner.path().unwrap());
- if let Err(e) = isolate.check_read(&path) {
+ if let Err(e) = cli.check_read(&path) {
return odd_future(e);
}
@@ -1269,10 +1267,10 @@ fn op_read_dir(
}
fn op_write_file(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
let inner = base.inner_as_write_file().unwrap();
let filename = String::from(inner.filename().unwrap());
let update_perm = inner.update_perm();
@@ -1280,7 +1278,7 @@ fn op_write_file(
let is_create = inner.is_create();
let is_append = inner.is_append();
- if let Err(e) = isolate.check_write(&filename) {
+ if let Err(e) = cli.check_write(&filename) {
return odd_future(e);
}
@@ -1299,16 +1297,16 @@ fn op_write_file(
}
fn op_rename(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_rename().unwrap();
let oldpath = PathBuf::from(inner.oldpath().unwrap());
let newpath_ = inner.newpath().unwrap();
let newpath = PathBuf::from(newpath_);
- if let Err(e) = isolate.check_write(&newpath_) {
+ if let Err(e) = cli.check_write(&newpath_) {
return odd_future(e);
}
blocking(base.sync(), move || -> OpResult {
@@ -1319,17 +1317,17 @@ fn op_rename(
}
fn op_symlink(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_symlink().unwrap();
let oldname = PathBuf::from(inner.oldname().unwrap());
let newname_ = inner.newname().unwrap();
let newname = PathBuf::from(newname_);
- if let Err(e) = isolate.check_write(&newname_) {
+ if let Err(e) = cli.check_write(&newname_) {
return odd_future(e);
}
// TODO Use type for Windows.
@@ -1348,17 +1346,17 @@ fn op_symlink(
}
fn op_read_link(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_readlink().unwrap();
let cmd_id = base.cmd_id();
let name_ = inner.name().unwrap();
let name = PathBuf::from(name_);
- if let Err(e) = isolate.check_read(&name_) {
+ if let Err(e) = cli.check_read(&name_) {
return odd_future(e);
}
@@ -1386,17 +1384,17 @@ fn op_read_link(
}
fn op_repl_start(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl_start().unwrap();
let cmd_id = base.cmd_id();
let history_file = String::from(inner.history_file().unwrap());
debug!("op_repl_start {}", history_file);
- let history_path = repl::history_path(&isolate.state.dir, &history_file);
+ let history_path = repl::history_path(&cli.state.dir, &history_file);
let repl = repl::Repl::new(history_path);
let resource = resources::add_repl(repl);
@@ -1417,10 +1415,10 @@ fn op_repl_start(
}
fn op_repl_readline(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl_readline().unwrap();
let cmd_id = base.cmd_id();
@@ -1453,17 +1451,17 @@ fn op_repl_readline(
}
fn op_truncate(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_truncate().unwrap();
let filename = String::from(inner.name().unwrap());
let len = inner.len();
- if let Err(e) = isolate.check_write(&filename) {
+ if let Err(e) = cli.check_write(&filename) {
return odd_future(e);
}
@@ -1476,12 +1474,12 @@ fn op_truncate(
}
fn op_listen(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
- if let Err(e) = isolate.check_net("listen") {
+ if let Err(e) = cli.check_net("listen") {
return odd_future(e);
}
@@ -1538,12 +1536,12 @@ fn new_conn(cmd_id: u32, tcp_stream: TcpStream) -> OpResult {
}
fn op_accept(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
- if let Err(e) = isolate.check_net("accept") {
+ if let Err(e) = cli.check_net("accept") {
return odd_future(e);
}
let cmd_id = base.cmd_id();
@@ -1564,12 +1562,12 @@ fn op_accept(
}
fn op_dial(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
- if let Err(e) = isolate.check_net("dial") {
+ if let Err(e) = cli.check_net("dial") {
return odd_future(e);
}
let cmd_id = base.cmd_id();
@@ -1590,17 +1588,17 @@ fn op_dial(
}
fn op_metrics(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let builder = &mut FlatBufferBuilder::new();
let inner = msg::MetricsRes::create(
builder,
- &msg::MetricsResArgs::from(&isolate.state.metrics),
+ &msg::MetricsResArgs::from(&cli.state.metrics),
);
ok_future(serialize_response(
cmd_id,
@@ -1614,10 +1612,10 @@ fn op_metrics(
}
fn op_resources(
- _isolate: &Isolate,
+ _cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
@@ -1665,15 +1663,11 @@ fn subprocess_stdio_map(v: msg::ProcessStdio) -> std::process::Stdio {
}
}
-fn op_run(
- isolate: &Isolate,
- base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+fn op_run(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError> {
assert!(base.sync());
let cmd_id = base.cmd_id();
- if let Err(e) = isolate.check_run() {
+ if let Err(e) = cli.check_run() {
return odd_future(e);
}
@@ -1739,16 +1733,16 @@ fn op_run(
}
fn op_run_status(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let inner = base.inner_as_run_status().unwrap();
let rid = inner.rid();
- if let Err(e) = isolate.check_run() {
+ if let Err(e) = cli.check_run() {
return odd_future(e);
}
@@ -1815,15 +1809,15 @@ impl Future for GetMessageFuture {
}
fn op_worker_get_message(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let op = GetMessageFuture {
- state: isolate.state.clone(),
+ state: cli.state.clone(),
};
let op = op.map_err(move |_| -> DenoError { unimplemented!() });
let op = op.and_then(move |maybe_buf| -> DenoResult<Buf> {
@@ -1849,16 +1843,16 @@ fn op_worker_get_message(
}
fn op_worker_post_message(
- isolate: &Isolate,
+ cli: &Cli,
base: &msg::Base<'_>,
- data: libdeno::deno_buf,
-) -> Box<Op> {
+ data: deno_buf,
+) -> Box<OpWithError> {
let cmd_id = base.cmd_id();
let d = Vec::from(data.as_ref()).into_boxed_slice();
- assert!(isolate.state.worker_channels.is_some());
- let tx = match isolate.state.worker_channels {
+ assert!(cli.state.worker_channels.is_some());
+ let tx = match cli.state.worker_channels {
None => panic!("expected worker_channels"),
Some(ref wc) => {
let wc = wc.lock().unwrap();
@@ -1884,13 +1878,13 @@ fn op_worker_post_message(
#[cfg(test)]
mod tests {
use super::*;
- use crate::isolate::{Isolate, IsolateState};
+ use crate::cli::Cli;
use crate::isolate_init::IsolateInit;
use crate::permissions::{DenoPermissions, PermissionAccessor};
#[test]
fn fetch_module_meta_fails_without_read() {
- let state = IsolateState::mock();
+ let state = Arc::new(IsolateState::mock());
let permissions = DenoPermissions {
allow_write: PermissionAccessor::from(true),
allow_env: PermissionAccessor::from(true),
@@ -1898,13 +1892,12 @@ mod tests {
allow_run: PermissionAccessor::from(true),
..Default::default()
};
- let isolate = Isolate::new(
+ let cli = Cli::new(
IsolateInit {
snapshot: None,
init_script: None,
},
state,
- dispatch,
permissions,
);
let builder = &mut FlatBufferBuilder::new();
@@ -1922,11 +1915,8 @@ mod tests {
msg::finish_base_buffer(builder, base);
let data = builder.finished_data();
let final_msg = msg::get_root_as_base(&data);
- let fetch_result = op_fetch_module_meta_data(
- &isolate,
- &final_msg,
- libdeno::deno_buf::empty(),
- ).wait();
+ let fetch_result =
+ op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait();
match fetch_result {
Ok(_) => assert!(true),
Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()),
@@ -1935,7 +1925,7 @@ mod tests {
#[test]
fn fetch_module_meta_fails_without_write() {
- let state = IsolateState::mock();
+ let state = Arc::new(IsolateState::mock());
let permissions = DenoPermissions {
allow_read: PermissionAccessor::from(true),
allow_env: PermissionAccessor::from(true),
@@ -1943,13 +1933,12 @@ mod tests {
allow_run: PermissionAccessor::from(true),
..Default::default()
};
- let isolate = Isolate::new(
+ let cli = Cli::new(
IsolateInit {
snapshot: None,
init_script: None,
},
state,
- dispatch,
permissions,
);
let builder = &mut FlatBufferBuilder::new();
@@ -1967,11 +1956,8 @@ mod tests {
msg::finish_base_buffer(builder, base);
let data = builder.finished_data();
let final_msg = msg::get_root_as_base(&data);
- let fetch_result = op_fetch_module_meta_data(
- &isolate,
- &final_msg,
- libdeno::deno_buf::empty(),
- ).wait();
+ let fetch_result =
+ op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait();
match fetch_result {
Ok(_) => assert!(true),
Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()),
@@ -1980,7 +1966,7 @@ mod tests {
#[test]
fn fetch_module_meta_fails_without_net() {
- let state = IsolateState::mock();
+ let state = Arc::new(IsolateState::mock());
let permissions = DenoPermissions {
allow_read: PermissionAccessor::from(true),
allow_write: PermissionAccessor::from(true),
@@ -1988,13 +1974,12 @@ mod tests {
allow_run: PermissionAccessor::from(true),
..Default::default()
};
- let isolate = Isolate::new(
+ let cli = Cli::new(
IsolateInit {
snapshot: None,
init_script: None,
},
state,
- dispatch,
permissions,
);
let builder = &mut FlatBufferBuilder::new();
@@ -2012,11 +1997,8 @@ mod tests {
msg::finish_base_buffer(builder, base);
let data = builder.finished_data();
let final_msg = msg::get_root_as_base(&data);
- let fetch_result = op_fetch_module_meta_data(
- &isolate,
- &final_msg,
- libdeno::deno_buf::empty(),
- ).wait();
+ let fetch_result =
+ op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait();
match fetch_result {
Ok(_) => assert!(true),
Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()),
@@ -2025,20 +2007,19 @@ mod tests {
#[test]
fn fetch_module_meta_not_permission_denied_with_permissions() {
- let state = IsolateState::mock();
+ let state = Arc::new(IsolateState::mock());
let permissions = DenoPermissions {
allow_read: PermissionAccessor::from(true),
allow_write: PermissionAccessor::from(true),
allow_net: PermissionAccessor::from(true),
..Default::default()
};
- let isolate = Isolate::new(
+ let cli = Cli::new(
IsolateInit {
snapshot: None,
init_script: None,
},
state,
- dispatch,
permissions,
);
let builder = &mut FlatBufferBuilder::new();
@@ -2056,11 +2037,8 @@ mod tests {
msg::finish_base_buffer(builder, base);
let data = builder.finished_data();
let final_msg = msg::get_root_as_base(&data);
- let fetch_result = op_fetch_module_meta_data(
- &isolate,
- &final_msg,
- libdeno::deno_buf::empty(),
- ).wait();
+ let fetch_result =
+ op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait();
match fetch_result {
Ok(_) => assert!(true),
Err(e) => assert!(e.to_string() != permission_denied().to_string()),
diff --git a/src/resources.rs b/src/resources.rs
index 2d617265e..e962bce8e 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -8,6 +8,7 @@
// descriptors". This module implements a global resource table. Ops (AKA
// handlers) look up resources by their integer id here.
+use crate::cli::Buf;
#[cfg(unix)]
use crate::eager_unix as eager;
use crate::errors;
@@ -15,8 +16,7 @@ use crate::errors::bad_resource;
use crate::errors::DenoError;
use crate::errors::DenoResult;
use crate::http_body::HttpBody;
-use crate::isolate::Buf;
-use crate::isolate::WorkerChannels;
+use crate::isolate_state::WorkerChannels;
use crate::repl::Repl;
use crate::tokio_util;
use crate::tokio_write;
@@ -175,50 +175,12 @@ impl Resource {
}
}
- /// Track the current task (for TcpListener resource).
- /// Throws an error if another task is already tracked.
- pub fn track_task(&mut self) -> Result<(), std::io::Error> {
- let mut table = RESOURCE_TABLE.lock().unwrap();
- // Only track if is TcpListener.
- if let Some(Repr::TcpListener(_, t)) = table.get_mut(&self.rid) {
- // Currently, we only allow tracking a single accept task for a listener.
- // This might be changed in the future with multiple workers.
- // Caveat: TcpListener by itself also only tracks an accept task at a time.
- // See https://github.com/tokio-rs/tokio/issues/846#issuecomment-454208883
- if t.is_some() {
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
- "Another accept task is ongoing",
- ));
- }
- t.replace(futures::task::current());
- }
- Ok(())
- }
-
- /// Stop tracking a task (for TcpListener resource).
- /// Happens when the task is done and thus no further tracking is needed.
- pub fn untrack_task(&mut self) {
- let mut table = RESOURCE_TABLE.lock().unwrap();
- // Only untrack if is TcpListener.
- if let Some(Repr::TcpListener(_, t)) = table.get_mut(&self.rid) {
- // DO NOT assert is_some here.
- // See reasoning in Accept::poll().
- t.take();
- }
- }
-
// close(2) is done by dropping the value. Therefore we just need to remove
// the resource from the RESOURCE_TABLE.
pub fn close(&self) {
let mut table = RESOURCE_TABLE.lock().unwrap();
let r = table.remove(&self.rid);
assert!(r.is_some());
- // If TcpListener, we must kill all pending accepts!
- if let Repr::TcpListener(_, Some(t)) = r.unwrap() {
- // Call notify on the tracked task, so that they would error out.
- t.notify();
- }
}
pub fn shutdown(&mut self, how: Shutdown) -> Result<(), DenoError> {
diff --git a/src/tokio_util.rs b/src/tokio_util.rs
index ef66f4610..810b826b4 100644
--- a/src/tokio_util.rs
+++ b/src/tokio_util.rs
@@ -1,6 +1,5 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::resources::Resource;
-
use futures;
use futures::Future;
use futures::Poll;
@@ -9,7 +8,14 @@ use std::mem;
use std::net::SocketAddr;
use tokio;
use tokio::net::TcpStream;
-use tokio_executor;
+
+pub fn run<F>(future: F)
+where
+ F: Future<Item = (), Error = ()> + Send + 'static,
+{
+ // tokio::runtime::current_thread::run(future)
+ tokio::run(future)
+}
pub fn block_on<F, R, E>(future: F) -> Result<R, E>
where
@@ -25,10 +31,12 @@ where
// Set the default executor so we can use tokio::spawn(). It's difficult to
// pass around mut references to the runtime, so using with_default is
// preferable. Ideally Tokio would provide this function.
+#[cfg(test)]
pub fn init<F>(f: F)
where
F: FnOnce(),
{
+ use tokio_executor;
let rt = tokio::runtime::Runtime::new().unwrap();
let mut executor = rt.executor();
let mut enter = tokio_executor::enter().expect("Multiple executors at once");
@@ -63,29 +71,7 @@ impl Future for Accept {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let (stream, addr) = match self.state {
- // Similar to try_ready!, but also track/untrack accept task
- // in TcpListener resource.
- // In this way, when the listener is closed, the task can be
- // notified to error out (instead of stuck forever).
- AcceptState::Pending(ref mut r) => match r.poll_accept() {
- Ok(futures::prelude::Async::Ready(t)) => {
- // Notice: it is possible to be Ready on the first poll.
- // When eager accept fails due to WouldBlock,
- // a next poll() might still be immediately Ready.
- // See https://github.com/denoland/deno/issues/1756.
- r.untrack_task();
- t
- }
- Ok(futures::prelude::Async::NotReady) => {
- // Would error out if another accept task is being tracked.
- r.track_task()?;
- return Ok(futures::prelude::Async::NotReady);
- }
- Err(e) => {
- r.untrack_task();
- return Err(e);
- }
- },
+ AcceptState::Pending(ref mut r) => try_ready!(r.poll_accept()),
AcceptState::Empty => panic!("poll Accept after it's done"),
};
diff --git a/src/workers.rs b/src/workers.rs
index 3a3b690b2..8393de222 100644
--- a/src/workers.rs
+++ b/src/workers.rs
@@ -1,19 +1,21 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-use crate::isolate::Buf;
+use crate::cli::Buf;
+use crate::cli::Cli;
+use crate::flags::DenoFlags;
use crate::isolate::Isolate;
-use crate::isolate::IsolateState;
-use crate::isolate::WorkerChannels;
use crate::isolate_init::IsolateInit;
+use crate::isolate_state::IsolateState;
+use crate::isolate_state::WorkerChannels;
use crate::js_errors::JSErrorColor;
-use crate::ops;
use crate::permissions::DenoPermissions;
use crate::resources;
use crate::tokio_util;
use deno_core::JSError;
-
+use futures::future::lazy;
use futures::sync::mpsc;
use futures::sync::oneshot;
use futures::Future;
+use futures::Poll;
use std::sync::Arc;
use std::thread;
@@ -25,7 +27,8 @@ pub struct Worker {
impl Worker {
pub fn new(
init: IsolateInit,
- parent_state: &Arc<IsolateState>,
+ flags: DenoFlags,
+ argv: Vec<String>,
permissions: DenoPermissions,
) -> (Self, WorkerChannels) {
let (worker_in_tx, worker_in_rx) = mpsc::channel::<Buf>(1);
@@ -34,30 +37,33 @@ impl Worker {
let internal_channels = (worker_out_tx, worker_in_rx);
let external_channels = (worker_in_tx, worker_out_rx);
- let state = Arc::new(IsolateState::new(
- parent_state.flags.clone(),
- parent_state.argv.clone(),
- Some(internal_channels),
- ));
+ let state =
+ Arc::new(IsolateState::new(flags, argv, Some(internal_channels)));
- let isolate = Isolate::new(init, state, ops::dispatch, permissions);
+ let cli = Cli::new(init, state, permissions);
+ let isolate = Isolate::new(cli);
let worker = Worker { isolate };
(worker, external_channels)
}
- pub fn execute(&self, js_source: &str) -> Result<(), JSError> {
+ pub fn execute(&mut self, js_source: &str) -> Result<(), JSError> {
self.isolate.execute(js_source)
}
+}
- pub fn event_loop(&self) -> Result<(), JSError> {
- self.isolate.event_loop()
+impl Future for Worker {
+ type Item = ();
+ type Error = JSError;
+
+ fn poll(&mut self) -> Poll<(), JSError> {
+ self.isolate.poll()
}
}
pub fn spawn(
init: IsolateInit,
- state: Arc<IsolateState>,
+ state: &IsolateState,
js_source: String,
permissions: DenoPermissions,
) -> resources::Resource {
@@ -67,27 +73,38 @@ pub fn spawn(
// let (js_error_tx, js_error_rx) = oneshot::channel::<JSError>();
let (p, c) = oneshot::channel::<resources::Resource>();
let builder = thread::Builder::new().name("worker".to_string());
- let _tid = builder
- .spawn(move || {
- let (worker, external_channels) = Worker::new(init, &state, permissions);
- let resource = resources::add_worker(external_channels);
- p.send(resource.clone()).unwrap();
+ let flags = state.flags.clone();
+ let argv = state.argv.clone();
- tokio_util::init(|| {
- (|| -> Result<(), JSError> {
- worker.execute("denoMain()")?;
- worker.execute("workerMain()")?;
- worker.execute(&js_source)?;
- worker.event_loop()?;
+ let _tid = builder
+ .spawn(move || {
+ tokio_util::run(lazy(move || {
+ let (mut worker, external_channels) =
+ Worker::new(init, flags, argv, permissions);
+ let resource = resources::add_worker(external_channels);
+ p.send(resource.clone()).unwrap();
+
+ worker
+ .execute("denoMain()")
+ .expect("worker denoMain failed");
+ worker
+ .execute("workerMain()")
+ .expect("worker workerMain failed");
+ worker.execute(&js_source).expect("worker js_source failed");
+
+ worker.then(move |r| -> Result<(), ()> {
+ resource.close();
+ debug!("workers.rs after resource close");
+ if let Err(err) = r {
+ eprintln!("{}", JSErrorColor(&err).to_string());
+ std::process::exit(1);
+ }
Ok(())
- })().or_else(|err: JSError| -> Result<(), JSError> {
- eprintln!("{}", JSErrorColor(&err).to_string());
- std::process::exit(1)
- }).unwrap();
- });
+ })
+ }));
- resource.close();
+ debug!("workers.rs after spawn");
}).unwrap();
c.wait().unwrap()
@@ -103,7 +120,7 @@ mod tests {
let isolate_init = isolate_init::compiler_isolate_init();
let resource = spawn(
isolate_init,
- IsolateState::mock(),
+ &IsolateState::mock(),
r#"
onmessage = function(e) {
let s = new TextDecoder().decode(e.data);;
@@ -140,7 +157,7 @@ mod tests {
let isolate_init = isolate_init::compiler_isolate_init();
let resource = spawn(
isolate_init,
- IsolateState::mock(),
+ &IsolateState::mock(),
"onmessage = () => close();".into(),
DenoPermissions::default(),
);