rusty_v8/
script_compiler.rs

1// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
2use std::{marker::PhantomData, mem::MaybeUninit};
3
4use crate::Function;
5use crate::Local;
6use crate::Module;
7use crate::Object;
8use crate::ScriptOrigin;
9use crate::String;
10use crate::{Context, Isolate, Script, UnboundScript};
11use crate::{HandleScope, UniqueRef};
12
13extern "C" {
14  fn v8__ScriptCompiler__Source__CONSTRUCT(
15    buf: *mut MaybeUninit<Source>,
16    source_string: *const String,
17    origin: *const ScriptOrigin,
18    cached_data: *mut CachedData,
19  );
20  fn v8__ScriptCompiler__Source__DESTRUCT(this: *mut Source);
21  fn v8__ScriptCompiler__Source__GetCachedData<'a>(
22    this: *const Source,
23  ) -> *const CachedData<'a>;
24  fn v8__ScriptCompiler__CachedData__NEW<'a>(
25    data: *const u8,
26    length: i32,
27  ) -> *mut CachedData<'a>;
28  fn v8__ScriptCompiler__CachedData__DELETE<'a>(this: *mut CachedData<'a>);
29  fn v8__ScriptCompiler__CompileModule(
30    isolate: *mut Isolate,
31    source: *mut Source,
32    options: CompileOptions,
33    no_cache_reason: NoCacheReason,
34  ) -> *const Module;
35  fn v8__ScriptCompiler__Compile(
36    context: *const Context,
37    source: *mut Source,
38    options: CompileOptions,
39    no_cache_reason: NoCacheReason,
40  ) -> *const Script;
41  fn v8__ScriptCompiler__CompileFunctionInContext(
42    context: *const Context,
43    source: *mut Source,
44    arguments_count: usize,
45    arguments: *const *const String,
46    context_extensions_count: usize,
47    context_extensions: *const *const Object,
48    options: CompileOptions,
49    no_cache_reason: NoCacheReason,
50  ) -> *const Function;
51  fn v8__ScriptCompiler__CompileUnboundScript(
52    isolate: *mut Isolate,
53    source: *mut Source,
54    options: CompileOptions,
55    no_cache_reason: NoCacheReason,
56  ) -> *const UnboundScript;
57}
58
59/// Source code which can then be compiled to a UnboundScript or Script.
60#[repr(C)]
61#[derive(Debug)]
62pub struct Source([usize; 8]);
63
64/// Compilation data that the embedder can cache and pass back to speed up future
65/// compilations. The data is produced if the CompilerOptions passed to the compilation
66/// functions in ScriptCompiler contains produce_data_to_cache = true. The data to cache
67/// can then can be retrieved from UnboundScript.
68#[repr(C)]
69#[derive(Debug)]
70pub struct CachedData<'a> {
71  data: *const u8,
72  length: i32,
73  rejected: bool,
74  buffer_policy: BufferPolicy,
75  _phantom: PhantomData<&'a ()>,
76}
77
78impl<'a> Drop for CachedData<'a> {
79  fn drop(&mut self) {
80    unsafe {
81      v8__ScriptCompiler__CachedData__DELETE(self);
82    }
83  }
84}
85
86impl<'a> CachedData<'a> {
87  pub fn new(data: &'a [u8]) -> UniqueRef<Self> {
88    unsafe {
89      UniqueRef::from_raw(v8__ScriptCompiler__CachedData__NEW(
90        data.as_ptr(),
91        data.len() as i32,
92      ))
93    }
94  }
95}
96
97impl<'a> std::ops::Deref for CachedData<'a> {
98  type Target = [u8];
99  fn deref(&self) -> &Self::Target {
100    unsafe { std::slice::from_raw_parts(self.data, self.length as usize) }
101  }
102}
103
104#[repr(C)]
105#[derive(Debug)]
106enum BufferPolicy {
107  BufferNotOwned = 0,
108  BufferOwned,
109}
110
111impl Source {
112  pub fn new(
113    source_string: Local<String>,
114    origin: Option<&ScriptOrigin>,
115  ) -> Self {
116    let mut buf = MaybeUninit::<Self>::uninit();
117    unsafe {
118      v8__ScriptCompiler__Source__CONSTRUCT(
119        &mut buf,
120        &*source_string,
121        origin.map(|x| x as *const _).unwrap_or(std::ptr::null()),
122        std::ptr::null_mut(),
123      );
124      buf.assume_init()
125    }
126  }
127
128  pub fn new_with_cached_data(
129    source_string: Local<String>,
130    origin: Option<&ScriptOrigin>,
131    cached_data: UniqueRef<CachedData>,
132  ) -> Self {
133    let mut buf = MaybeUninit::<Self>::uninit();
134    unsafe {
135      v8__ScriptCompiler__Source__CONSTRUCT(
136        &mut buf,
137        &*source_string,
138        origin.map(|x| x as *const _).unwrap_or(std::ptr::null()),
139        cached_data.into_raw(), // Source constructor takes ownership.
140      );
141      buf.assume_init()
142    }
143  }
144
145  pub fn get_cached_data(&self) -> &CachedData {
146    unsafe { &*v8__ScriptCompiler__Source__GetCachedData(self) }
147  }
148}
149
150impl Drop for Source {
151  fn drop(&mut self) {
152    unsafe { v8__ScriptCompiler__Source__DESTRUCT(self) }
153  }
154}
155
156#[repr(C)]
157#[derive(Debug)]
158pub enum CompileOptions {
159  NoCompileOptions = 0,
160  ConsumeCodeCache,
161  EagerCompile,
162}
163
164/// The reason for which we are not requesting or providing a code cache.
165#[repr(C)]
166#[derive(Debug)]
167pub enum NoCacheReason {
168  NoReason = 0,
169  BecauseCachingDisabled,
170  BecauseNoResource,
171  BecauseInlineScript,
172  BecauseModule,
173  BecauseStreamingSource,
174  BecauseInspector,
175  BecauseScriptTooSmall,
176  BecauseCacheTooCold,
177  BecauseV8Extension,
178  BecauseExtensionModule,
179  BecausePacScript,
180  BecauseInDocumentWrite,
181  BecauseResourceWithNoCacheHandler,
182  BecauseDeferredProduceCodeCache,
183}
184
185/// Compile an ES module, returning a Module that encapsulates the compiled
186/// code.
187///
188/// Corresponds to the ParseModule abstract operation in the ECMAScript
189/// specification.
190pub fn compile_module<'s>(
191  scope: &mut HandleScope<'s>,
192  source: Source,
193) -> Option<Local<'s, Module>> {
194  compile_module2(
195    scope,
196    source,
197    CompileOptions::NoCompileOptions,
198    NoCacheReason::NoReason,
199  )
200}
201
202/// Same as compile_module with more options.
203pub fn compile_module2<'s>(
204  scope: &mut HandleScope<'s>,
205  mut source: Source,
206  options: CompileOptions,
207  no_cache_reason: NoCacheReason,
208) -> Option<Local<'s, Module>> {
209  unsafe {
210    scope.cast_local(|sd| {
211      v8__ScriptCompiler__CompileModule(
212        sd.get_isolate_ptr(),
213        &mut source,
214        options,
215        no_cache_reason,
216      )
217    })
218  }
219}
220
221pub fn compile<'s>(
222  scope: &mut HandleScope<'s>,
223  mut source: Source,
224  options: CompileOptions,
225  no_cache_reason: NoCacheReason,
226) -> Option<Local<'s, Script>> {
227  unsafe {
228    scope.cast_local(|sd| {
229      v8__ScriptCompiler__Compile(
230        &*sd.get_current_context(),
231        &mut source,
232        options,
233        no_cache_reason,
234      )
235    })
236  }
237}
238
239pub fn compile_function_in_context<'s>(
240  scope: &mut HandleScope<'s>,
241  mut source: Source,
242  arguments: &[Local<String>],
243  context_extensions: &[Local<Object>],
244  options: CompileOptions,
245  no_cache_reason: NoCacheReason,
246) -> Option<Local<'s, Function>> {
247  let arguments = Local::slice_into_raw(arguments);
248  let context_extensions = Local::slice_into_raw(context_extensions);
249  unsafe {
250    scope.cast_local(|sd| {
251      v8__ScriptCompiler__CompileFunctionInContext(
252        &*sd.get_current_context(),
253        &mut source,
254        arguments.len(),
255        arguments.as_ptr(),
256        context_extensions.len(),
257        context_extensions.as_ptr(),
258        options,
259        no_cache_reason,
260      )
261    })
262  }
263}
264
265pub fn compile_unbound_script<'s>(
266  scope: &mut HandleScope<'s>,
267  mut source: Source,
268  options: CompileOptions,
269  no_cache_reason: NoCacheReason,
270) -> Option<Local<'s, UnboundScript>> {
271  unsafe {
272    scope.cast_local(|sd| {
273      v8__ScriptCompiler__CompileUnboundScript(
274        sd.get_isolate_ptr(),
275        &mut source,
276        options,
277        no_cache_reason,
278      )
279    })
280  }
281}