1use 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::UniqueRef;
11use crate::isolate::RealIsolate;
12use crate::scope::PinScope;
13use crate::support::int;
14use crate::{Context, Script, UnboundScript};
15
16unsafe extern "C" {
17 fn v8__ScriptCompiler__Source__CONSTRUCT(
18 buf: *mut MaybeUninit<Source>,
19 source_string: *const String,
20 origin: *const ScriptOrigin,
21 cached_data: *mut CachedData,
22 );
23 fn v8__ScriptCompiler__Source__DESTRUCT(this: *mut Source);
24 fn v8__ScriptCompiler__Source__GetCachedData<'a>(
25 this: *const Source,
26 ) -> *const CachedData<'a>;
27 fn v8__ScriptCompiler__CachedData__NEW<'a>(
28 data: *const u8,
29 length: i32,
30 ) -> *mut CachedData<'a>;
31 fn v8__ScriptCompiler__CachedData__DELETE<'a>(this: *mut CachedData<'a>);
32 fn v8__ScriptCompiler__CompileModule(
33 isolate: *mut RealIsolate,
34 source: *mut Source,
35 options: CompileOptions,
36 no_cache_reason: NoCacheReason,
37 ) -> *const Module;
38 fn v8__ScriptCompiler__Compile(
39 context: *const Context,
40 source: *mut Source,
41 options: CompileOptions,
42 no_cache_reason: NoCacheReason,
43 ) -> *const Script;
44 fn v8__ScriptCompiler__CompileFunction(
45 context: *const Context,
46 source: *mut Source,
47 arguments_count: usize,
48 arguments: *const *const String,
49 context_extensions_count: usize,
50 context_extensions: *const *const Object,
51 options: CompileOptions,
52 no_cache_reason: NoCacheReason,
53 ) -> *const Function;
54 fn v8__ScriptCompiler__CompileUnboundScript(
55 isolate: *mut RealIsolate,
56 source: *mut Source,
57 options: CompileOptions,
58 no_cache_reason: NoCacheReason,
59 ) -> *const UnboundScript;
60
61 fn v8__ScriptCompiler__CachedDataVersionTag() -> u32;
62}
63
64#[repr(C)]
66#[derive(Debug)]
67pub struct Source {
68 _source_string: usize,
69 _resource_name: usize,
70 _resource_line_offset: int,
71 _resource_column_offset: int,
72 _resource_options: int,
73 _source_map_url: usize,
74 _host_defined_options: usize,
75 _cached_data: usize,
76 _consume_cache_task: usize,
77 _compile_hint_callback: usize,
78 _compile_hint_callback_data: usize,
79 _compilation_details: [usize; 3],
80}
81
82#[repr(C)]
87#[derive(Debug)]
88pub struct CachedData<'a> {
89 data: *const u8,
90 length: i32,
91 rejected: bool,
92 buffer_policy: BufferPolicy,
93 _phantom: PhantomData<&'a ()>,
94}
95
96impl Drop for CachedData<'_> {
97 fn drop(&mut self) {
98 unsafe {
99 v8__ScriptCompiler__CachedData__DELETE(self);
100 }
101 }
102}
103
104impl<'a> CachedData<'a> {
105 pub fn new(data: &'a [u8]) -> UniqueRef<Self> {
106 let cached_data = unsafe {
107 UniqueRef::from_raw(v8__ScriptCompiler__CachedData__NEW(
108 data.as_ptr(),
109 data.len() as i32,
110 ))
111 };
112 debug_assert_eq!(
113 cached_data.buffer_policy(),
114 crate::script_compiler::BufferPolicy::BufferNotOwned
115 );
116 cached_data
117 }
118
119 #[inline(always)]
120 pub(crate) fn buffer_policy(&self) -> BufferPolicy {
121 self.buffer_policy
122 }
123
124 #[inline(always)]
125 pub fn rejected(&self) -> bool {
126 self.rejected
127 }
128}
129
130impl std::ops::Deref for CachedData<'_> {
131 type Target = [u8];
132 fn deref(&self) -> &Self::Target {
133 unsafe { std::slice::from_raw_parts(self.data, self.length as usize) }
134 }
135}
136
137#[allow(dead_code)]
138#[repr(C)]
139#[derive(Clone, Copy, Debug, PartialEq)]
140pub(crate) enum BufferPolicy {
141 BufferNotOwned = 0,
142 BufferOwned,
143}
144
145impl Source {
146 #[inline(always)]
147 pub fn new(
148 source_string: Local<String>,
149 origin: Option<&ScriptOrigin>,
150 ) -> Self {
151 let mut buf = MaybeUninit::<Self>::uninit();
152 unsafe {
153 v8__ScriptCompiler__Source__CONSTRUCT(
154 &mut buf,
155 &*source_string,
156 origin.map_or(std::ptr::null(), |x| x as *const _),
157 std::ptr::null_mut(),
158 );
159 buf.assume_init()
160 }
161 }
162
163 #[inline(always)]
164 pub fn new_with_cached_data(
165 source_string: Local<String>,
166 origin: Option<&ScriptOrigin>,
167 cached_data: UniqueRef<CachedData>,
168 ) -> Self {
169 let mut buf = MaybeUninit::<Self>::uninit();
170 unsafe {
171 v8__ScriptCompiler__Source__CONSTRUCT(
172 &mut buf,
173 &*source_string,
174 origin.map_or(std::ptr::null(), |x| x as *const _),
175 cached_data.into_raw(), );
177 buf.assume_init()
178 }
179 }
180
181 #[inline(always)]
182 pub fn get_cached_data(&self) -> Option<&CachedData<'_>> {
183 unsafe {
184 let cached_data = v8__ScriptCompiler__Source__GetCachedData(self);
185 if cached_data.is_null() {
186 None
187 } else {
188 Some(&*cached_data)
189 }
190 }
191 }
192}
193
194impl Drop for Source {
195 fn drop(&mut self) {
196 unsafe { v8__ScriptCompiler__Source__DESTRUCT(self) }
197 }
198}
199
200bitflags! {
201 #[derive(Debug, Clone, Copy, PartialEq)]
202 #[repr(transparent)]
203 pub struct CompileOptions: int {
204 const NoCompileOptions = 0;
205 const ConsumeCodeCache = 1 << 0;
206 const EagerCompile = 1 << 1;
207 const ProduceCompileHints = 1 << 2;
208 const ConsumeCompileHints = 1 << 3;
209 const FollowCompileHintsMagicComment = 1 << 4;
210 const FollowCompileHintsPerFunctionMagicComment = 1 << 5;
211 }
212}
213
214#[repr(C)]
216#[derive(Debug)]
217pub enum NoCacheReason {
218 NoReason = 0,
219 BecauseCachingDisabled,
220 BecauseNoResource,
221 BecauseInlineScript,
222 BecauseModule,
223 BecauseStreamingSource,
224 BecauseInspector,
225 BecauseScriptTooSmall,
226 BecauseCacheTooCold,
227 BecauseV8Extension,
228 BecauseExtensionModule,
229 BecausePacScript,
230 BecauseInDocumentWrite,
231 BecauseResourceWithNoCacheHandler,
232 BecauseDeferredProduceCodeCache,
233}
234
235#[inline(always)]
241pub fn compile_module<'s>(
242 scope: &PinScope<'s, '_>,
243 source: &mut Source,
244) -> Option<Local<'s, Module>> {
245 compile_module2(
246 scope,
247 source,
248 CompileOptions::NoCompileOptions,
249 NoCacheReason::NoReason,
250 )
251}
252
253#[inline(always)]
255pub fn compile_module2<'s>(
256 scope: &PinScope<'s, '_>,
257 source: &mut Source,
258 options: CompileOptions,
259 no_cache_reason: NoCacheReason,
260) -> Option<Local<'s, Module>> {
261 unsafe {
262 scope.cast_local(|sd| {
263 v8__ScriptCompiler__CompileModule(
264 sd.get_isolate_ptr(),
265 source,
266 options,
267 no_cache_reason,
268 )
269 })
270 }
271}
272
273#[inline(always)]
274pub fn compile<'s>(
275 scope: &PinScope<'s, '_>,
276 source: &mut Source,
277 options: CompileOptions,
278 no_cache_reason: NoCacheReason,
279) -> Option<Local<'s, Script>> {
280 unsafe {
281 scope.cast_local(|sd| {
282 v8__ScriptCompiler__Compile(
283 &*sd.get_current_context(),
284 source,
285 options,
286 no_cache_reason,
287 )
288 })
289 }
290}
291
292#[inline(always)]
293pub fn compile_function<'s>(
294 scope: &PinScope<'s, '_>,
295 source: &mut Source,
296 arguments: &[Local<String>],
297 context_extensions: &[Local<Object>],
298 options: CompileOptions,
299 no_cache_reason: NoCacheReason,
300) -> Option<Local<'s, Function>> {
301 let arguments = Local::slice_into_raw(arguments);
302 let context_extensions = Local::slice_into_raw(context_extensions);
303 unsafe {
304 scope.cast_local(|sd| {
305 v8__ScriptCompiler__CompileFunction(
306 &*sd.get_current_context(),
307 source,
308 arguments.len(),
309 arguments.as_ptr(),
310 context_extensions.len(),
311 context_extensions.as_ptr(),
312 options,
313 no_cache_reason,
314 )
315 })
316 }
317}
318
319#[inline(always)]
320pub fn compile_unbound_script<'s>(
321 scope: &PinScope<'s, '_>,
322 source: &mut Source,
323 options: CompileOptions,
324 no_cache_reason: NoCacheReason,
325) -> Option<Local<'s, UnboundScript>> {
326 unsafe {
327 scope.cast_local(|sd| {
328 v8__ScriptCompiler__CompileUnboundScript(
329 sd.get_isolate_ptr(),
330 source,
331 options,
332 no_cache_reason,
333 )
334 })
335 }
336}
337
338#[inline(always)]
354pub fn cached_data_version_tag() -> u32 {
355 unsafe { v8__ScriptCompiler__CachedDataVersionTag() }
356}