summaryrefslogtreecommitdiff
path: root/core/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'core/lib.rs')
-rw-r--r--core/lib.rs364
1 files changed, 14 insertions, 350 deletions
diff --git a/core/lib.rs b/core/lib.rs
index 6416704e2..66233ddfc 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -1,364 +1,28 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
#[macro_use]
extern crate log;
extern crate futures;
extern crate libc;
+mod flags;
+mod isolate;
mod js_errors;
mod libdeno;
-mod shared;
+pub use crate::flags::v8_set_flags;
+pub use crate::isolate::*;
pub use crate::js_errors::*;
pub use crate::libdeno::deno_buf;
-pub use crate::shared::*;
-use futures::Async;
-use futures::Future;
-use futures::Poll;
-use libc::c_void;
-use std::collections::HashMap;
-use std::ffi::CStr;
-use std::ffi::CString;
-use std::sync::{Once, ONCE_INIT};
+pub use crate::libdeno::deno_mod;
-pub struct Isolate {
- libdeno_isolate: *const libdeno::isolate,
- pending_ops: HashMap<i32, PendingOp>, // promise_id -> op
- polled_recently: bool,
- recv_cb: RecvCallback,
-
- pub shared: Shared,
- pub test_send_counter: u32, // TODO only used for testing- REMOVE.
-}
-
-pub type RecvCallback = fn(isolate: &mut Isolate, zero_copy_buf: deno_buf);
-
-pub const NUM_RECORDS: usize = 100;
-
-// TODO rename to AsyncResult
-pub struct AsyncResult {
- pub result: i32,
-}
-
-pub type Op = dyn Future<Item = AsyncResult, Error = std::io::Error> + Send;
-
-struct PendingOp {
- op: Box<Op>,
- polled_recently: bool,
- zero_copy_id: usize, // non-zero if associated zero-copy buffer.
-}
-
-static DENO_INIT: Once = ONCE_INIT;
-
-unsafe impl Send for Isolate {}
-
-impl Isolate {
- pub fn new(recv_cb: RecvCallback) -> Self {
- DENO_INIT.call_once(|| {
- unsafe { libdeno::deno_init() };
- });
-
- // Allocate unmanaged memory for the shared buffer by creating a Vec<u8>,
- // grabbing the raw pointer, and then leaking the Vec so it is never freed.
- let mut shared = Shared::new();
- let shared_deno_buf = shared.as_deno_buf();
-
- let config = libdeno::deno_config {
- will_snapshot: 0,
- load_snapshot: deno_buf::empty(), // TODO
- shared: shared_deno_buf,
- recv_cb: pre_dispatch,
- };
- let libdeno_isolate = unsafe { libdeno::deno_new(config) };
-
- Self {
- pending_ops: HashMap::new(),
- polled_recently: false,
- libdeno_isolate,
- test_send_counter: 0,
- recv_cb,
- shared,
- }
- }
-
- fn zero_copy_release(&self, zero_copy_id: usize) {
- unsafe {
- libdeno::deno_zero_copy_release(self.libdeno_isolate, zero_copy_id)
- }
- }
-
- pub fn add_op(
- self: &mut Self,
- promise_id: i32,
- op: Box<Op>,
- zero_copy_id: usize,
- ) {
- debug!("add_op {}", zero_copy_id);
- self.pending_ops.insert(
- promise_id,
- PendingOp {
- op,
- polled_recently: false,
- zero_copy_id,
- },
- );
- self.polled_recently = false;
- }
-
- #[inline]
- pub unsafe fn from_raw_ptr<'a>(ptr: *const c_void) -> &'a mut Self {
- let ptr = ptr as *mut _;
- &mut *ptr
- }
-
- #[inline]
- pub fn as_raw_ptr(&self) -> *const c_void {
- self as *const _ as *const c_void
- }
-
- pub fn execute(
- &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 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();
- Some(js_error)
- }
- }
-
- fn check_promise_errors(&self) {
- unsafe {
- libdeno::deno_check_promise_errors(self.libdeno_isolate);
- }
- }
-
- fn respond(&mut self) -> Result<(), JSError> {
- let buf = deno_buf::empty();
- unsafe {
- libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), buf)
- }
- if let Some(err) = self.last_exception() {
- Err(err)
- } else {
- Ok(())
- }
- }
-}
-
-struct LockerScope {
- libdeno_isolate: *const libdeno::isolate,
+pub fn v8_version() -> &'static str {
+ use std::ffi::CStr;
+ let version = unsafe { libdeno::deno_v8_version() };
+ let c_str = unsafe { CStr::from_ptr(version) };
+ c_str.to_str().unwrap()
}
-impl LockerScope {
- fn new(isolate: &Isolate) -> LockerScope {
- let libdeno_isolate = isolate.libdeno_isolate;
- unsafe { libdeno::deno_lock(libdeno_isolate) }
- LockerScope { libdeno_isolate }
- }
-}
-
-impl Drop for LockerScope {
- fn drop(&mut self) {
- unsafe { libdeno::deno_unlock(self.libdeno_isolate) }
- }
-}
-
-impl Future for Isolate {
- type Item = ();
- type Error = JSError;
-
- fn poll(&mut self) -> Poll<(), JSError> {
- // Lock the current thread for V8.
- let _locker = LockerScope::new(self);
-
- // Clear
- self.polled_recently = false;
- for (_, pending) in self.pending_ops.iter_mut() {
- pending.polled_recently = false;
- }
-
- while !self.polled_recently {
- let mut complete = HashMap::<i32, AsyncResult>::new();
-
- self.polled_recently = true;
- for (promise_id, pending) in self.pending_ops.iter_mut() {
- // Do not call poll on futures we've already polled this turn.
- if pending.polled_recently {
- continue;
- }
- pending.polled_recently = true;
-
- let promise_id = *promise_id;
- let op = &mut pending.op;
- match op.poll() {
- Err(op_err) => {
- eprintln!("op err {:?}", op_err);
- complete.insert(promise_id, AsyncResult { result: -1 });
- debug!("pending op {} complete err", promise_id);
- }
- Ok(Async::Ready(async_result)) => {
- complete.insert(promise_id, async_result);
- debug!("pending op {} complete ready", promise_id);
- }
- Ok(Async::NotReady) => {
- debug!("pending op {} not ready", promise_id);
- continue;
- }
- }
- }
-
- self.shared.set_num_records(complete.len() as i32);
- if complete.len() > 0 {
- // self.zero_copy_release() and self.respond() need Locker.
- let mut i = 0;
- for (promise_id, async_result) in complete.iter_mut() {
- let pending = self.pending_ops.remove(promise_id).unwrap();
-
- if pending.zero_copy_id > 0 {
- self.zero_copy_release(pending.zero_copy_id);
- }
-
- self
- .shared
- .set_record(i, RECORD_OFFSET_PROMISE_ID, *promise_id);
- self
- .shared
- .set_record(i, RECORD_OFFSET_RESULT, async_result.result);
- i += 1;
- }
- self.respond()?;
- }
- }
-
- self.check_promise_errors();
- if let Some(err) = self.last_exception() {
- return Err(err);
- }
-
- // We're idle if pending_ops is empty.
- if self.pending_ops.is_empty() {
- Ok(futures::Async::Ready(()))
- } else {
- Ok(futures::Async::NotReady)
- }
- }
-}
-
-extern "C" fn pre_dispatch(
- user_data: *mut c_void,
- control_buf: deno_buf,
- zero_copy_buf: deno_buf,
-) {
- let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
- assert_eq!(control_buf.len(), 0);
- (isolate.recv_cb)(isolate, zero_copy_buf);
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn inc_counter(isolate: &mut Isolate, zero_copy_buf: deno_buf) {
- assert_eq!(zero_copy_buf.len(), 0);
- isolate.test_send_counter += 1; // TODO ideally store this in isolate.state?
- }
-
- fn js_check(r: Result<(), JSError>) {
- if let Err(e) = r {
- panic!(e.to_string());
- }
- }
-
- #[test]
- fn test_execute() {
- let isolate = Isolate::new(inc_counter);
- js_check(isolate.execute(
- "filename.js",
- r#"
- libdeno.send();
- async function main() {
- libdeno.send();
- }
- main();
- "#,
- ));
- // We expect that main is executed even tho we didn't poll.
- assert_eq!(isolate.test_send_counter, 2);
- }
-
- fn async_immediate(isolate: &mut Isolate, zero_copy_buf: deno_buf) {
- assert_eq!(zero_copy_buf.len(), 0);
- isolate.test_send_counter += 1; // TODO ideally store this in isolate.state?
-
- let promise_id = 0;
- let op = Box::new(futures::future::ok(AsyncResult { result: 0 }));
- isolate.add_op(promise_id, op, zero_copy_buf.zero_copy_id);
- }
-
- #[test]
- fn test_poll_async_immediate_ops() {
- let mut isolate = Isolate::new(async_immediate);
- js_check(isolate.execute(
- "setup.js",
- r#"
- let nrecv = 0;
- libdeno.recv(() => {
- nrecv++;
- });
- function assertEq(actual, expected) {
- if (expected != actual) {
- throw Error(`actual ${actual} expected ${expected} `);
- }
- }
- "#,
- ));
- assert_eq!(isolate.test_send_counter, 0);
- js_check(isolate.execute(
- "check1.js",
- r#"
- assertEq(nrecv, 0);
- libdeno.send();
- assertEq(nrecv, 0);
- "#,
- ));
- assert_eq!(isolate.test_send_counter, 1);
- assert_eq!(Ok(Async::Ready(())), isolate.poll());
- assert_eq!(isolate.test_send_counter, 1);
- js_check(isolate.execute(
- "check2.js",
- r#"
- assertEq(nrecv, 1);
- libdeno.send();
- assertEq(nrecv, 1);
- "#,
- ));
- assert_eq!(isolate.test_send_counter, 2);
- assert_eq!(Ok(Async::Ready(())), isolate.poll());
- js_check(isolate.execute("check3.js", "assertEq(nrecv, 2)"));
- assert_eq!(isolate.test_send_counter, 2);
- // We are idle, so the next poll should be the last.
- assert_eq!(Ok(Async::Ready(())), isolate.poll());
- }
+#[test]
+fn test_v8_version() {
+ assert!(v8_version().len() > 3);
}