Skip to content

Commit

Permalink
Separate behavior for the compiler isolate (denoland#1973)
Browse files Browse the repository at this point in the history
  • Loading branch information
afinch7 authored and ry committed Mar 20, 2019
1 parent 6131152 commit 48bf419
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 293 deletions.
57 changes: 57 additions & 0 deletions cli/cli_behavior.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate_state::*;
use crate::ops;
use deno_core::deno_buf;
use deno_core::deno_mod;
use deno_core::Behavior;
use deno_core::Op;
use deno_core::StartupData;
use std::sync::Arc;

/// Implements deno_core::Behavior for the main Deno command-line.
pub struct CliBehavior {
startup_data: Option<StartupData>,
pub state: Arc<IsolateState>,
}

impl CliBehavior {
pub fn new(
startup_data: Option<StartupData>,
state: Arc<IsolateState>,
) -> Self {
Self {
startup_data,
state,
}
}
}

impl IsolateStateContainer for &CliBehavior {
fn state(&self) -> Arc<IsolateState> {
self.state.clone()
}
}

impl IsolateStateContainer for CliBehavior {
fn state(&self) -> Arc<IsolateState> {
self.state.clone()
}
}

impl Behavior for CliBehavior {
fn startup_data(&mut self) -> Option<StartupData> {
self.startup_data.take()
}

fn resolve(&mut self, specifier: &str, referrer: deno_mod) -> deno_mod {
self.state_resolve(specifier, referrer)
}

fn dispatch(
&mut self,
control: &[u8],
zero_copy: deno_buf,
) -> (bool, Box<Op>) {
ops::dispatch_all(Box::new(self), control, zero_copy, ops::op_selector_std)
}
}
93 changes: 77 additions & 16 deletions cli/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,84 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate_state::IsolateState;
use crate::isolate_state::*;
use crate::msg;
use crate::permissions::{DenoPermissions, PermissionAccessor};
use crate::ops;
use crate::resources;
use crate::resources::Resource;
use crate::resources::ResourceId;
use crate::startup_data;
use crate::workers;
use crate::workers::WorkerBehavior;
use deno_core::deno_buf;
use deno_core::deno_mod;
use deno_core::Behavior;
use deno_core::Buf;
use deno_core::Op;
use deno_core::StartupData;
use futures::Future;
use serde_json;
use std::str;
use std::sync::Arc;
use std::sync::Mutex;

lazy_static! {
static ref C_RID: Mutex<Option<ResourceId>> = Mutex::new(None);
}

pub struct CompilerBehavior {
pub state: Arc<IsolateState>,
}

impl CompilerBehavior {
pub fn new(state: Arc<IsolateState>) -> Self {
Self { state }
}
}

impl IsolateStateContainer for CompilerBehavior {
fn state(&self) -> Arc<IsolateState> {
self.state.clone()
}
}

impl IsolateStateContainer for &CompilerBehavior {
fn state(&self) -> Arc<IsolateState> {
self.state.clone()
}
}

impl Behavior for CompilerBehavior {
fn startup_data(&mut self) -> Option<StartupData> {
Some(startup_data::compiler_isolate_init())
}

fn resolve(&mut self, specifier: &str, referrer: deno_mod) -> deno_mod {
self.state_resolve(specifier, referrer)
}

fn dispatch(
&mut self,
control: &[u8],
zero_copy: deno_buf,
) -> (bool, Box<Op>) {
ops::dispatch_all(
Box::new(self),
control,
zero_copy,
ops::op_selector_compiler,
)
}
}

impl WorkerBehavior for CompilerBehavior {
fn set_internal_channels(&mut self, worker_channels: WorkerChannels) {
self.state = Arc::new(IsolateState::new(
self.state.flags.clone(),
self.state.argv.clone(),
Some(worker_channels),
));
}
}

// This corresponds to JS ModuleMetaData.
// TODO Rename one or the other so they correspond.
#[derive(Debug)]
Expand Down Expand Up @@ -46,22 +108,16 @@ impl ModuleMetaData {
}
}

fn lazy_start(parent_state: &IsolateState) -> Resource {
fn lazy_start(parent_state: Arc<IsolateState>) -> Resource {
let mut cell = C_RID.lock().unwrap();
let startup_data = startup_data::compiler_isolate_init();
let permissions = DenoPermissions {
allow_read: PermissionAccessor::from(true),
allow_write: PermissionAccessor::from(true),
allow_net: PermissionAccessor::from(true),
..Default::default()
};

let rid = cell.get_or_insert_with(|| {
let resource = workers::spawn(
Some(startup_data),
parent_state,
CompilerBehavior::new(Arc::new(IsolateState::new(
parent_state.flags.clone(),
parent_state.argv.clone(),
None,
))),
"compilerMain()".to_string(),
permissions,
);
resource.rid
});
Expand All @@ -78,7 +134,7 @@ fn req(specifier: &str, referrer: &str) -> Buf {
}

pub fn compile_sync(
parent_state: &IsolateState,
parent_state: Arc<IsolateState>,
specifier: &str,
referrer: &str,
module_meta_data: &ModuleMetaData,
Expand Down Expand Up @@ -140,7 +196,12 @@ mod tests {
maybe_source_map: None,
};

out = compile_sync(&IsolateState::mock(), specifier, &referrer, &mut out);
out = compile_sync(
Arc::new(IsolateState::mock()),
specifier,
&referrer,
&mut out,
);
assert!(
out
.maybe_output_code
Expand Down
4 changes: 4 additions & 0 deletions cli/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ pub fn permission_denied() -> DenoError {
)
}

pub fn op_not_implemented() -> DenoError {
new(ErrorKind::BadResource, String::from("op not implemented"))
}

#[derive(Debug)]
pub enum RustOrJsError {
Rust(DenoError),
Expand Down
30 changes: 17 additions & 13 deletions cli/isolate.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::cli::Cli;
use crate::compiler::compile_sync;
use crate::compiler::ModuleMetaData;
use crate::errors::DenoError;
use crate::errors::RustOrJsError;
use crate::isolate_state::IsolateState;
use crate::isolate_state::IsolateStateContainer;
use crate::js_errors;
use crate::msg;
use deno_core;
use deno_core::deno_mod;
use deno_core::Behavior;
use deno_core::JSError;
use futures::Async;
use futures::Future;
use std::sync::Arc;

type CoreIsolate = deno_core::Isolate<Cli>;
pub trait DenoBehavior: Behavior + IsolateStateContainer + Send {}
impl<T> DenoBehavior for T where T: Behavior + IsolateStateContainer + Send {}

type CoreIsolate<B> = deno_core::Isolate<B>;

/// Wraps deno_core::Isolate to provide source maps, ops for the CLI, and
/// high-level module loading
pub struct Isolate {
inner: CoreIsolate,
pub struct Isolate<B: Behavior> {
inner: CoreIsolate<B>,
state: Arc<IsolateState>,
}

impl Isolate {
pub fn new(cli: Cli) -> Isolate {
let state = cli.state.clone();
impl<B: DenoBehavior> Isolate<B> {
pub fn new(behavior: B) -> Isolate<B> {
let state = behavior.state().clone();
Self {
inner: CoreIsolate::new(cli),
inner: CoreIsolate::new(behavior),
state,
}
}
Expand Down Expand Up @@ -150,7 +154,7 @@ impl Isolate {
}
}

impl Future for Isolate {
impl<B: DenoBehavior> Future for Isolate<B> {
type Item = ();
type Error = JSError;

Expand All @@ -170,7 +174,7 @@ fn fetch_module_meta_data_and_maybe_compile(
|| state.flags.recompile
{
debug!(">>>>> compile_sync START");
out = compile_sync(state, specifier, &referrer, &out);
out = compile_sync(state.clone(), specifier, &referrer, &out);
debug!(">>>>> compile_sync END");
state.dir.code_cache(&out)?;
}
Expand All @@ -180,8 +184,8 @@ fn fetch_module_meta_data_and_maybe_compile(
#[cfg(test)]
mod tests {
use super::*;
use crate::cli_behavior::CliBehavior;
use crate::flags;
use crate::permissions::DenoPermissions;
use crate::tokio_util;
use futures::future::lazy;
use std::sync::atomic::Ordering;
Expand All @@ -199,7 +203,7 @@ mod tests {
let state = Arc::new(IsolateState::new(flags, rest_argv, None));
let state_ = state.clone();
tokio_util::run(lazy(move || {
let cli = Cli::new(None, state.clone(), DenoPermissions::default());
let cli = CliBehavior::new(None, state.clone());
let mut isolate = Isolate::new(cli);
if let Err(err) = isolate.execute_mod(&filename, false) {
eprintln!("execute_mod err {:?}", err);
Expand All @@ -222,7 +226,7 @@ mod tests {
let state = Arc::new(IsolateState::new(flags, rest_argv, None));
let state_ = state.clone();
tokio_util::run(lazy(move || {
let cli = Cli::new(None, state.clone(), DenoPermissions::default());
let cli = CliBehavior::new(None, state.clone());
let mut isolate = Isolate::new(cli);
if let Err(err) = isolate.execute_mod(&filename, false) {
eprintln!("execute_mod err {:?}", err);
Expand Down
49 changes: 49 additions & 0 deletions cli/isolate_state.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::deno_dir;
use crate::errors::DenoResult;
use crate::flags;
use crate::global_timer::GlobalTimer;
use crate::modules::Modules;
use crate::permissions::DenoPermissions;
use deno_core::deno_mod;
use deno_core::Buf;
use futures::sync::mpsc as async_mpsc;
use std;
use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::sync::Mutex;

pub type WorkerSender = async_mpsc::Sender<Buf>;
Expand All @@ -33,6 +37,7 @@ pub struct Metrics {
pub struct IsolateState {
pub dir: deno_dir::DenoDir,
pub argv: Vec<String>,
pub permissions: DenoPermissions,
pub flags: flags::DenoFlags,
pub metrics: Metrics,
pub modules: Mutex<Modules>,
Expand All @@ -52,6 +57,7 @@ impl IsolateState {
dir: deno_dir::DenoDir::new(flags.reload, flags.recompile, custom_root)
.unwrap(),
argv: argv_rest,
permissions: DenoPermissions::from_flags(&flags),
flags,
metrics: Metrics::default(),
modules: Mutex::new(Modules::new()),
Expand All @@ -76,6 +82,31 @@ impl IsolateState {
}
}

#[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()
}

#[cfg(test)]
pub fn mock() -> IsolateState {
let argv = vec![String::from("./deno"), String::from("hello.js")];
Expand Down Expand Up @@ -108,3 +139,21 @@ impl IsolateState {
.fetch_add(bytes_received, Ordering::SeqCst);
}
}

/// Provides state getter function
pub trait IsolateStateContainer {
fn state(&self) -> Arc<IsolateState>;
}

/// Provides state_resolve function for IsolateStateContainer implementors
pub trait IsolateStateModuleResolution: IsolateStateContainer {
fn state_resolve(&mut self, specifier: &str, referrer: deno_mod) -> deno_mod {
let state = self.state();
state.metrics.resolve_count.fetch_add(1, Ordering::Relaxed);
let mut modules = state.modules.lock().unwrap();
modules.resolve_cb(&state.dir, specifier, referrer)
}
}

// Auto implementation for all IsolateStateContainer implementors
impl<T> IsolateStateModuleResolution for T where T: IsolateStateContainer {}
Loading

0 comments on commit 48bf419

Please sign in to comment.