mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-27 01:29:19 -05:00
68c0466b1f
Updated "build/" submodule and adjusted to V8 API changes.
342 lines
8.7 KiB
Rust
342 lines
8.7 KiB
Rust
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
|
use std::{marker::PhantomData, mem::MaybeUninit};
|
|
|
|
use crate::support::int;
|
|
use crate::Function;
|
|
use crate::Local;
|
|
use crate::Module;
|
|
use crate::Object;
|
|
use crate::ScriptOrigin;
|
|
use crate::String;
|
|
use crate::{Context, Isolate, Script, UnboundScript};
|
|
use crate::{HandleScope, UniqueRef};
|
|
|
|
extern "C" {
|
|
fn v8__ScriptCompiler__Source__CONSTRUCT(
|
|
buf: *mut MaybeUninit<Source>,
|
|
source_string: *const String,
|
|
origin: *const ScriptOrigin,
|
|
cached_data: *mut CachedData,
|
|
);
|
|
fn v8__ScriptCompiler__Source__DESTRUCT(this: *mut Source);
|
|
fn v8__ScriptCompiler__Source__GetCachedData<'a>(
|
|
this: *const Source,
|
|
) -> *const CachedData<'a>;
|
|
fn v8__ScriptCompiler__CachedData__NEW<'a>(
|
|
data: *const u8,
|
|
length: i32,
|
|
) -> *mut CachedData<'a>;
|
|
fn v8__ScriptCompiler__CachedData__DELETE<'a>(this: *mut CachedData<'a>);
|
|
fn v8__ScriptCompiler__CompileModule(
|
|
isolate: *mut Isolate,
|
|
source: *mut Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> *const Module;
|
|
fn v8__ScriptCompiler__Compile(
|
|
context: *const Context,
|
|
source: *mut Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> *const Script;
|
|
fn v8__ScriptCompiler__CompileFunction(
|
|
context: *const Context,
|
|
source: *mut Source,
|
|
arguments_count: usize,
|
|
arguments: *const *const String,
|
|
context_extensions_count: usize,
|
|
context_extensions: *const *const Object,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> *const Function;
|
|
fn v8__ScriptCompiler__CompileUnboundScript(
|
|
isolate: *mut Isolate,
|
|
source: *mut Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> *const UnboundScript;
|
|
|
|
fn v8__ScriptCompiler__CachedDataVersionTag() -> u32;
|
|
}
|
|
|
|
/// Source code which can then be compiled to a UnboundScript or Script.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct Source {
|
|
_source_string: usize,
|
|
_resource_name: usize,
|
|
_resource_line_offset: int,
|
|
_resource_column_offset: int,
|
|
_resource_options: int,
|
|
_source_map_url: usize,
|
|
_host_defined_options: usize,
|
|
_cached_data: usize,
|
|
_consume_cache_task: usize,
|
|
_compile_hint_callback: usize,
|
|
_compile_hint_callback_data: usize,
|
|
}
|
|
|
|
/// Compilation data that the embedder can cache and pass back to speed up future
|
|
/// compilations. The data is produced if the CompilerOptions passed to the compilation
|
|
/// functions in ScriptCompiler contains produce_data_to_cache = true. The data to cache
|
|
/// can then can be retrieved from UnboundScript.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct CachedData<'a> {
|
|
data: *const u8,
|
|
length: i32,
|
|
rejected: bool,
|
|
buffer_policy: BufferPolicy,
|
|
_phantom: PhantomData<&'a ()>,
|
|
}
|
|
|
|
impl<'a> Drop for CachedData<'a> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
v8__ScriptCompiler__CachedData__DELETE(self);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> CachedData<'a> {
|
|
pub fn new(data: &'a [u8]) -> UniqueRef<Self> {
|
|
let cached_data = unsafe {
|
|
UniqueRef::from_raw(v8__ScriptCompiler__CachedData__NEW(
|
|
data.as_ptr(),
|
|
data.len() as i32,
|
|
))
|
|
};
|
|
debug_assert_eq!(
|
|
cached_data.buffer_policy(),
|
|
crate::script_compiler::BufferPolicy::BufferNotOwned
|
|
);
|
|
cached_data
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn buffer_policy(&self) -> BufferPolicy {
|
|
self.buffer_policy
|
|
}
|
|
}
|
|
|
|
impl<'a> std::ops::Deref for CachedData<'a> {
|
|
type Target = [u8];
|
|
fn deref(&self) -> &Self::Target {
|
|
unsafe { std::slice::from_raw_parts(self.data, self.length as usize) }
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub(crate) enum BufferPolicy {
|
|
BufferNotOwned = 0,
|
|
BufferOwned,
|
|
}
|
|
|
|
impl Source {
|
|
#[inline(always)]
|
|
pub fn new(
|
|
source_string: Local<String>,
|
|
origin: Option<&ScriptOrigin>,
|
|
) -> Self {
|
|
let mut buf = MaybeUninit::<Self>::uninit();
|
|
unsafe {
|
|
v8__ScriptCompiler__Source__CONSTRUCT(
|
|
&mut buf,
|
|
&*source_string,
|
|
origin.map(|x| x as *const _).unwrap_or(std::ptr::null()),
|
|
std::ptr::null_mut(),
|
|
);
|
|
buf.assume_init()
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn new_with_cached_data(
|
|
source_string: Local<String>,
|
|
origin: Option<&ScriptOrigin>,
|
|
cached_data: UniqueRef<CachedData>,
|
|
) -> Self {
|
|
let mut buf = MaybeUninit::<Self>::uninit();
|
|
unsafe {
|
|
v8__ScriptCompiler__Source__CONSTRUCT(
|
|
&mut buf,
|
|
&*source_string,
|
|
origin.map(|x| x as *const _).unwrap_or(std::ptr::null()),
|
|
cached_data.into_raw(), // Source constructor takes ownership.
|
|
);
|
|
buf.assume_init()
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn get_cached_data(&self) -> Option<&CachedData> {
|
|
unsafe {
|
|
let cached_data = v8__ScriptCompiler__Source__GetCachedData(self);
|
|
if cached_data.is_null() {
|
|
None
|
|
} else {
|
|
Some(&*cached_data)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for Source {
|
|
fn drop(&mut self) {
|
|
unsafe { v8__ScriptCompiler__Source__DESTRUCT(self) }
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub enum CompileOptions {
|
|
NoCompileOptions = 0,
|
|
ConsumeCodeCache,
|
|
EagerCompile,
|
|
}
|
|
|
|
/// The reason for which we are not requesting or providing a code cache.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub enum NoCacheReason {
|
|
NoReason = 0,
|
|
BecauseCachingDisabled,
|
|
BecauseNoResource,
|
|
BecauseInlineScript,
|
|
BecauseModule,
|
|
BecauseStreamingSource,
|
|
BecauseInspector,
|
|
BecauseScriptTooSmall,
|
|
BecauseCacheTooCold,
|
|
BecauseV8Extension,
|
|
BecauseExtensionModule,
|
|
BecausePacScript,
|
|
BecauseInDocumentWrite,
|
|
BecauseResourceWithNoCacheHandler,
|
|
BecauseDeferredProduceCodeCache,
|
|
}
|
|
|
|
/// Compile an ES module, returning a Module that encapsulates the compiled
|
|
/// code.
|
|
///
|
|
/// Corresponds to the ParseModule abstract operation in the ECMAScript
|
|
/// specification.
|
|
#[inline(always)]
|
|
pub fn compile_module<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
source: Source,
|
|
) -> Option<Local<'s, Module>> {
|
|
compile_module2(
|
|
scope,
|
|
source,
|
|
CompileOptions::NoCompileOptions,
|
|
NoCacheReason::NoReason,
|
|
)
|
|
}
|
|
|
|
/// Same as compile_module with more options.
|
|
#[inline(always)]
|
|
pub fn compile_module2<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
mut source: Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> Option<Local<'s, Module>> {
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__ScriptCompiler__CompileModule(
|
|
sd.get_isolate_ptr(),
|
|
&mut source,
|
|
options,
|
|
no_cache_reason,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn compile<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
mut source: Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> Option<Local<'s, Script>> {
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__ScriptCompiler__Compile(
|
|
&*sd.get_current_context(),
|
|
&mut source,
|
|
options,
|
|
no_cache_reason,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn compile_function<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
mut source: Source,
|
|
arguments: &[Local<String>],
|
|
context_extensions: &[Local<Object>],
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> Option<Local<'s, Function>> {
|
|
let arguments = Local::slice_into_raw(arguments);
|
|
let context_extensions = Local::slice_into_raw(context_extensions);
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__ScriptCompiler__CompileFunction(
|
|
&*sd.get_current_context(),
|
|
&mut source,
|
|
arguments.len(),
|
|
arguments.as_ptr(),
|
|
context_extensions.len(),
|
|
context_extensions.as_ptr(),
|
|
options,
|
|
no_cache_reason,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn compile_unbound_script<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
mut source: Source,
|
|
options: CompileOptions,
|
|
no_cache_reason: NoCacheReason,
|
|
) -> Option<Local<'s, UnboundScript>> {
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__ScriptCompiler__CompileUnboundScript(
|
|
sd.get_isolate_ptr(),
|
|
&mut source,
|
|
options,
|
|
no_cache_reason,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Return a version tag for CachedData for the current V8 version & flags.
|
|
///
|
|
/// This value is meant only for determining whether a previously generated
|
|
/// CachedData instance is still valid; the tag has no other meaing.
|
|
///
|
|
/// Background: The data carried by CachedData may depend on the exact V8
|
|
/// version number or current compiler flags. This means that when persisting
|
|
/// CachedData, the embedder must take care to not pass in data from another V8
|
|
/// version, or the same version with different features enabled.
|
|
///
|
|
/// The easiest way to do so is to clear the embedder's cache on any such
|
|
/// change.
|
|
///
|
|
/// Alternatively, this tag can be stored alongside the cached data and compared
|
|
/// when it is being used.
|
|
#[inline(always)]
|
|
pub fn cached_data_version_tag() -> u32 {
|
|
unsafe { v8__ScriptCompiler__CachedDataVersionTag() }
|
|
}
|