1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-11 00:21:05 -05:00
denoland-deno/core/libdeno.rs
2020-01-06 16:24:44 +01:00

449 lines
12 KiB
Rust

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#![allow(mutable_transmutes)]
#![allow(clippy::transmute_ptr_to_ptr)]
use crate::bindings;
use rusty_v8 as v8;
use libc::c_char;
use libc::c_void;
use std::convert::From;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::null;
use std::ptr::NonNull;
use std::slice;
pub type OpId = u32;
pub struct ModuleInfo {
pub main: bool,
pub name: String,
pub handle: v8::Global<v8::Module>,
pub import_specifiers: Vec<String>,
}
pub fn script_origin<'a>(
s: &mut impl v8::ToLocal<'a>,
resource_name: v8::Local<'a, v8::String>,
) -> v8::ScriptOrigin<'a> {
let resource_line_offset = v8::Integer::new(s, 0);
let resource_column_offset = v8::Integer::new(s, 0);
let resource_is_shared_cross_origin = v8::Boolean::new(s, false);
let script_id = v8::Integer::new(s, 123);
let source_map_url = v8::String::new(s, "source_map_url").unwrap();
let resource_is_opaque = v8::Boolean::new(s, true);
let is_wasm = v8::Boolean::new(s, false);
let is_module = v8::Boolean::new(s, false);
v8::ScriptOrigin::new(
resource_name.into(),
resource_line_offset,
resource_column_offset,
resource_is_shared_cross_origin,
script_id,
source_map_url.into(),
resource_is_opaque,
is_wasm,
is_module,
)
}
pub fn module_origin<'a>(
s: &mut impl v8::ToLocal<'a>,
resource_name: v8::Local<'a, v8::String>,
) -> v8::ScriptOrigin<'a> {
let resource_line_offset = v8::Integer::new(s, 0);
let resource_column_offset = v8::Integer::new(s, 0);
let resource_is_shared_cross_origin = v8::Boolean::new(s, false);
let script_id = v8::Integer::new(s, 123);
let source_map_url = v8::String::new(s, "source_map_url").unwrap();
let resource_is_opaque = v8::Boolean::new(s, true);
let is_wasm = v8::Boolean::new(s, false);
let is_module = v8::Boolean::new(s, true);
v8::ScriptOrigin::new(
resource_name.into(),
resource_line_offset,
resource_column_offset,
resource_is_shared_cross_origin,
script_id,
source_map_url.into(),
resource_is_opaque,
is_wasm,
is_module,
)
}
/// This type represents a borrowed slice.
#[repr(C)]
pub struct deno_buf {
pub data_ptr: *const u8,
pub data_len: 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 {
data_ptr: null(),
data_len: 0,
}
}
#[inline]
pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self {
Self {
data_ptr: ptr,
data_len: len,
}
}
}
/// Converts Rust &Buf to libdeno `deno_buf`.
impl<'a> From<&'a [u8]> for deno_buf {
#[inline]
fn from(x: &'a [u8]) -> Self {
Self {
data_ptr: x.as_ref().as_ptr(),
data_len: x.len(),
}
}
}
impl<'a> From<&'a mut [u8]> for deno_buf {
#[inline]
fn from(x: &'a mut [u8]) -> Self {
Self {
data_ptr: x.as_ref().as_ptr(),
data_len: x.len(),
}
}
}
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 AsRef<[u8]> for deno_buf {
#[inline]
fn as_ref(&self) -> &[u8] {
&*self
}
}
/// A PinnedBuf encapsulates a slice that's been borrowed from a JavaScript
/// ArrayBuffer object. JavaScript objects can normally be garbage collected,
/// but the existence of a PinnedBuf inhibits this until it is dropped. It
/// behaves much like an Arc<[u8]>, although a PinnedBuf currently can't be
/// cloned.
#[allow(unused)]
pub struct PinnedBuf {
data_ptr: NonNull<u8>,
data_len: usize,
backing_store: v8::SharedRef<v8::BackingStore>,
}
unsafe impl Send for PinnedBuf {}
impl PinnedBuf {
pub fn new(view: v8::Local<v8::ArrayBufferView>) -> Self {
let mut backing_store = view.buffer().unwrap().get_backing_store();
let backing_store_ptr = backing_store.data() as *mut _ as *mut u8;
let view_ptr = unsafe { backing_store_ptr.add(view.byte_offset()) };
let view_len = view.byte_length();
Self {
data_ptr: NonNull::new(view_ptr).unwrap(),
data_len: view_len,
backing_store,
}
}
}
impl Deref for PinnedBuf {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.data_ptr.as_ptr(), self.data_len) }
}
}
impl DerefMut for PinnedBuf {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.data_ptr.as_ptr(), self.data_len) }
}
}
impl AsRef<[u8]> for PinnedBuf {
fn as_ref(&self) -> &[u8] {
&*self
}
}
impl AsMut<[u8]> for PinnedBuf {
fn as_mut(&mut self) -> &mut [u8] {
&mut *self
}
}
#[repr(C)]
#[allow(unused)]
pub struct deno_snapshot<'a> {
pub data_ptr: *const u8,
pub data_len: usize,
_marker: PhantomData<&'a [u8]>,
}
/// `deno_snapshot` can not clone, and there is no interior mutability.
/// This type satisfies Send bound.
unsafe impl Send for deno_snapshot<'_> {}
// TODO(ry) Snapshot1 and Snapshot2 are not very good names and need to be
// reconsidered. The entire snapshotting interface is still under construction.
/// The type returned from deno_snapshot_new. Needs to be dropped.
pub type Snapshot1 = v8::OwnedStartupData;
#[allow(non_camel_case_types)]
pub type deno_mod = i32;
#[allow(non_camel_case_types)]
pub type deno_dyn_import_id = i32;
#[allow(non_camel_case_types)]
pub type deno_resolve_cb = unsafe extern "C" fn(
resolve_context: *mut c_void,
specifier: *const c_char,
referrer: deno_mod,
) -> deno_mod;
pub enum SnapshotConfig {
Borrowed(v8::StartupData<'static>),
Owned(v8::OwnedStartupData),
}
impl From<&'static [u8]> for SnapshotConfig {
fn from(sd: &'static [u8]) -> Self {
Self::Borrowed(v8::StartupData::new(sd))
}
}
impl From<v8::OwnedStartupData> for SnapshotConfig {
fn from(sd: v8::OwnedStartupData) -> Self {
Self::Owned(sd)
}
}
impl Deref for SnapshotConfig {
type Target = v8::StartupData<'static>;
fn deref(&self) -> &Self::Target {
match self {
Self::Borrowed(sd) => sd,
Self::Owned(sd) => &*sd,
}
}
}
pub unsafe fn deno_init() {
let platform = v8::platform::new_default_platform();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
// TODO(ry) This makes WASM compile synchronously. Eventually we should
// remove this to make it work asynchronously too. But that requires getting
// PumpMessageLoop and RunMicrotasks setup correctly.
// See https://github.com/denoland/deno/issues/2544
let argv = vec![
"".to_string(),
"--no-wasm-async-compilation".to_string(),
"--harmony-top-level-await".to_string(),
];
v8::V8::set_flags_from_command_line(argv);
}
lazy_static! {
pub static ref EXTERNAL_REFERENCES: v8::ExternalReferences =
v8::ExternalReferences::new(&[
v8::ExternalReference {
function: bindings::print
},
v8::ExternalReference {
function: bindings::recv
},
v8::ExternalReference {
function: bindings::send
},
v8::ExternalReference {
function: bindings::eval_context
},
v8::ExternalReference {
function: bindings::error_to_json
},
v8::ExternalReference {
getter: bindings::shared_getter
},
v8::ExternalReference {
message: bindings::message_callback
},
v8::ExternalReference {
function: bindings::queue_microtask
},
]);
}
pub fn initialize_context<'a>(
scope: &mut impl v8::ToLocal<'a>,
mut context: v8::Local<v8::Context>,
) {
context.enter();
let global = context.global(scope);
let deno_val = v8::Object::new(scope);
global.set(
context,
v8::String::new(scope, "Deno").unwrap().into(),
deno_val.into(),
);
let mut core_val = v8::Object::new(scope);
deno_val.set(
context,
v8::String::new(scope, "core").unwrap().into(),
core_val.into(),
);
let mut print_tmpl = v8::FunctionTemplate::new(scope, bindings::print);
let print_val = print_tmpl.get_function(scope, context).unwrap();
core_val.set(
context,
v8::String::new(scope, "print").unwrap().into(),
print_val.into(),
);
let mut recv_tmpl = v8::FunctionTemplate::new(scope, bindings::recv);
let recv_val = recv_tmpl.get_function(scope, context).unwrap();
core_val.set(
context,
v8::String::new(scope, "recv").unwrap().into(),
recv_val.into(),
);
let mut send_tmpl = v8::FunctionTemplate::new(scope, bindings::send);
let send_val = send_tmpl.get_function(scope, context).unwrap();
core_val.set(
context,
v8::String::new(scope, "send").unwrap().into(),
send_val.into(),
);
let mut eval_context_tmpl =
v8::FunctionTemplate::new(scope, bindings::eval_context);
let eval_context_val =
eval_context_tmpl.get_function(scope, context).unwrap();
core_val.set(
context,
v8::String::new(scope, "evalContext").unwrap().into(),
eval_context_val.into(),
);
let mut error_to_json_tmpl =
v8::FunctionTemplate::new(scope, bindings::error_to_json);
let error_to_json_val =
error_to_json_tmpl.get_function(scope, context).unwrap();
core_val.set(
context,
v8::String::new(scope, "errorToJSON").unwrap().into(),
error_to_json_val.into(),
);
core_val.set_accessor(
context,
v8::String::new(scope, "shared").unwrap().into(),
bindings::shared_getter,
);
// Direct bindings on `window`.
let mut queue_microtask_tmpl =
v8::FunctionTemplate::new(scope, bindings::queue_microtask);
let queue_microtask_val =
queue_microtask_tmpl.get_function(scope, context).unwrap();
global.set(
context,
v8::String::new(scope, "queueMicrotask").unwrap().into(),
queue_microtask_val.into(),
);
context.exit();
}
pub unsafe fn deno_import_buf<'sc>(
scope: &mut impl v8::ToLocal<'sc>,
buf: deno_buf,
) -> v8::Local<'sc, v8::Uint8Array> {
/*
if (buf.data_ptr == nullptr) {
return v8::Local<v8::Uint8Array>();
}
*/
if buf.data_ptr.is_null() {
let ab = v8::ArrayBuffer::new(scope, 0);
return v8::Uint8Array::new(ab, 0, 0).expect("Failed to create UintArray8");
}
/*
// To avoid excessively allocating new ArrayBuffers, we try to reuse a single
// global ArrayBuffer. The caveat is that users must extract data from it
// before the next tick. We only do this for ArrayBuffers less than 1024
// bytes.
v8::Local<v8::ArrayBuffer> ab;
void* data;
if (buf.data_len > GLOBAL_IMPORT_BUF_SIZE) {
// Simple case. We allocate a new ArrayBuffer for this.
ab = v8::ArrayBuffer::New(d->isolate_, buf.data_len);
data = ab->GetBackingStore()->Data();
} else {
// Fast case. We reuse the global ArrayBuffer.
if (d->global_import_buf_.IsEmpty()) {
// Lazily initialize it.
DCHECK_NULL(d->global_import_buf_ptr_);
ab = v8::ArrayBuffer::New(d->isolate_, GLOBAL_IMPORT_BUF_SIZE);
d->global_import_buf_.Reset(d->isolate_, ab);
d->global_import_buf_ptr_ = ab->GetBackingStore()->Data();
} else {
DCHECK(d->global_import_buf_ptr_);
ab = d->global_import_buf_.Get(d->isolate_);
}
data = d->global_import_buf_ptr_;
}
memcpy(data, buf.data_ptr, buf.data_len);
auto view = v8::Uint8Array::New(ab, 0, buf.data_len);
return view;
*/
// TODO(bartlomieju): for now skipping part with `global_import_buf_`
// and always creating new buffer
let ab = v8::ArrayBuffer::new(scope, buf.data_len);
let mut backing_store = ab.get_backing_store();
let data = backing_store.data();
let data: *mut u8 = data as *mut libc::c_void as *mut u8;
std::ptr::copy_nonoverlapping(buf.data_ptr, data, buf.data_len);
v8::Uint8Array::new(ab, 0, buf.data_len).expect("Failed to create UintArray8")
}
/*
#[allow(dead_code)]
pub unsafe fn deno_snapshot_delete(s: &mut deno_snapshot) {
todo!()
}
*/