From a6d36d11936933705069d6c4ce47f445f607597e Mon Sep 17 00:00:00 2001 From: Heyang Zhou Date: Sun, 7 Mar 2021 21:05:50 +0800 Subject: [PATCH] Add more ScriptCompiler APIs (#638) --- src/binding.cc | 30 +++++++++++++-- src/script_compiler.rs | 61 +++++++++++++++++++++++++++--- tests/test_api.rs | 85 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 158 insertions(+), 18 deletions(-) diff --git a/src/binding.cc b/src/binding.cc index 1049682a..4dd6a9cc 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -353,10 +353,15 @@ void v8__Global__Reset(const v8::Data* data) { void v8__ScriptCompiler__Source__CONSTRUCT( uninit_t* buf, const v8::String& source_string, - const v8::ScriptOrigin& origin, + const v8::ScriptOrigin* origin, v8::ScriptCompiler::CachedData* cached_data) { - construct_in_place( - buf, ptr_to_local(&source_string), origin, cached_data); + if (origin) { + construct_in_place( + buf, ptr_to_local(&source_string), *origin, cached_data); + } else { + construct_in_place( + buf, ptr_to_local(&source_string), cached_data); + } } void v8__ScriptCompiler__Source__DESTRUCT(v8::ScriptCompiler::Source* self) { @@ -388,6 +393,25 @@ const v8::Module* v8__ScriptCompiler__CompileModule( return maybe_local_to_ptr(maybe_local); } +const v8::Script* v8__ScriptCompiler__Compile( + const v8::Context* context, v8::ScriptCompiler::Source* source, + v8::ScriptCompiler::CompileOptions options, + v8::ScriptCompiler::NoCacheReason no_cache_reason) { + v8::MaybeLocal maybe_local = v8::ScriptCompiler::Compile( + ptr_to_local(context), source, options, no_cache_reason); + return maybe_local_to_ptr(maybe_local); +} + +const v8::UnboundScript* v8__ScriptCompiler__CompileUnboundScript( + v8::Isolate* isolate, v8::ScriptCompiler::Source* source, + v8::ScriptCompiler::CompileOptions options, + v8::ScriptCompiler::NoCacheReason no_cache_reason) { + v8::MaybeLocal maybe_local = + v8::ScriptCompiler::CompileUnboundScript(isolate, source, options, + no_cache_reason); + return maybe_local_to_ptr(maybe_local); +} + bool v8__Data__EQ(const v8::Data& self, const v8::Data& other) { return ptr_to_local(&self) == ptr_to_local(&other); } diff --git a/src/script_compiler.rs b/src/script_compiler.rs index 7b78da79..23865e48 100644 --- a/src/script_compiler.rs +++ b/src/script_compiler.rs @@ -1,11 +1,11 @@ // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. use std::{marker::PhantomData, mem::MaybeUninit}; -use crate::Isolate; use crate::Local; use crate::Module; use crate::ScriptOrigin; use crate::String; +use crate::{Context, Isolate, Script, UnboundScript}; use crate::{HandleScope, UniqueRef}; extern "C" { @@ -30,6 +30,18 @@ extern "C" { 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__CompileUnboundScript( + isolate: *mut Isolate, + source: *mut Source, + options: CompileOptions, + no_cache_reason: NoCacheReason, + ) -> *const UnboundScript; } /// Source code which can then be compiled to a UnboundScript or Script. @@ -85,13 +97,16 @@ enum BufferPolicy { } impl Source { - pub fn new(source_string: Local, origin: &ScriptOrigin) -> Self { + pub fn new( + source_string: Local, + origin: Option<&ScriptOrigin>, + ) -> Self { let mut buf = MaybeUninit::::uninit(); unsafe { v8__ScriptCompiler__Source__CONSTRUCT( &mut buf, &*source_string, - origin, + origin.map(|x| x as *const _).unwrap_or(std::ptr::null()), std::ptr::null_mut(), ); buf.assume_init() @@ -100,7 +115,7 @@ impl Source { pub fn new_with_cached_data( source_string: Local, - origin: &ScriptOrigin, + origin: Option<&ScriptOrigin>, cached_data: UniqueRef, ) -> Self { let mut buf = MaybeUninit::::uninit(); @@ -108,7 +123,7 @@ impl Source { v8__ScriptCompiler__Source__CONSTRUCT( &mut buf, &*source_string, - origin, + origin.map(|x| x as *const _).unwrap_or(std::ptr::null()), cached_data.into_raw(), // Source constructor takes ownership. ); buf.assume_init() @@ -190,3 +205,39 @@ pub fn compile_module2<'s>( }) } } + +pub fn compile<'s>( + scope: &mut HandleScope<'s>, + mut source: Source, + options: CompileOptions, + no_cache_reason: NoCacheReason, +) -> Option> { + unsafe { + scope.cast_local(|sd| { + v8__ScriptCompiler__Compile( + &*sd.get_current_context(), + &mut source, + options, + no_cache_reason, + ) + }) + } +} + +pub fn compile_unbound_script<'s>( + scope: &mut HandleScope<'s>, + mut source: Source, + options: CompileOptions, + no_cache_reason: NoCacheReason, +) -> Option> { + unsafe { + scope.cast_local(|sd| { + v8__ScriptCompiler__CompileUnboundScript( + sd.get_isolate_ptr(), + &mut source, + options, + no_cache_reason, + ) + }) + } +} diff --git a/tests/test_api.rs b/tests/test_api.rs index 81ee9b6a..d376a107 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -1911,7 +1911,7 @@ fn mock_source<'s>( ) -> v8::script_compiler::Source { let source_str = v8::String::new(scope, source).unwrap(); let script_origin = mock_script_origin(scope, resource_name); - v8::script_compiler::Source::new(source_str, &script_origin) + v8::script_compiler::Source::new(source_str, Some(&script_origin)) } #[test] @@ -1928,7 +1928,7 @@ fn script_compiler_source() { let script_origin = mock_script_origin(scope, "foo.js"); let source = v8::script_compiler::Source::new( v8::String::new(scope, source).unwrap(), - &script_origin, + Some(&script_origin), ); let result = v8::script_compiler::compile_module(scope, source); @@ -1952,7 +1952,7 @@ fn module_instantiation_failures1() { ) .unwrap(); let origin = mock_script_origin(scope, "foo.js"); - let source = v8::script_compiler::Source::new(source_text, &origin); + let source = v8::script_compiler::Source::new(source_text, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status()); @@ -2015,7 +2015,7 @@ fn compile_specifier_as_module_resolve_callback<'a>( ) -> Option> { let scope = &mut unsafe { v8::CallbackScope::new(context) }; let origin = mock_script_origin(scope, "module.js"); - let source = v8::script_compiler::Source::new(specifier, &origin); + let source = v8::script_compiler::Source::new(specifier, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); Some(module) } @@ -2036,7 +2036,7 @@ fn module_evaluation() { ) .unwrap(); let origin = mock_script_origin(scope, "foo.js"); - let source = v8::script_compiler::Source::new(source_text, &origin); + let source = v8::script_compiler::Source::new(source_text, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); assert!(module.script_id().is_some()); @@ -2088,7 +2088,7 @@ fn import_assertions() { let origin = mock_script_origin(scope, "module.js"); let src = v8::String::new(scope, "export const a = 'a';").unwrap(); - let source = v8::script_compiler::Source::new(src, &origin); + let source = v8::script_compiler::Source::new(src, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); Some(module) } @@ -2125,7 +2125,7 @@ fn import_assertions() { ) .unwrap(); let origin = mock_script_origin(scope, "foo.js"); - let source = v8::script_compiler::Source::new(source_text, &origin); + let source = v8::script_compiler::Source::new(source_text, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); assert!(module.script_id().is_some()); @@ -3723,7 +3723,7 @@ fn module_snapshot() { ) .unwrap(); let origin = mock_script_origin(scope, "foo.js"); - let source = v8::script_compiler::Source::new(source_text, &origin); + let source = v8::script_compiler::Source::new(source_text, Some(&origin)); let module = v8::script_compiler::compile_module(scope, source).unwrap(); assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status()); @@ -4807,10 +4807,10 @@ fn create_module<'s>( let source = match code_cache { Some(x) => v8::script_compiler::Source::new_with_cached_data( source, - &script_origin, + Some(&script_origin), x, ), - None => v8::script_compiler::Source::new(source, &script_origin), + None => v8::script_compiler::Source::new(source, Some(&script_origin)), }; let module = v8::script_compiler::compile_module2( scope, @@ -4894,3 +4894,68 @@ fn code_cache() { .unwrap(); assert_eq!(&value.to_rust_string_lossy(&mut scope), "world"); } + +#[test] +fn eager_compile_script() { + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let code = v8::String::new(scope, "1 + 1").unwrap(); + let source = v8::script_compiler::Source::new(code, None); + let script = v8::script_compiler::compile( + scope, + source, + v8::script_compiler::CompileOptions::EagerCompile, + v8::script_compiler::NoCacheReason::NoReason, + ) + .unwrap(); + let ret = script.run(scope).unwrap(); + assert_eq!(ret.uint32_value(scope).unwrap(), 2); +} + +#[test] +fn code_cache_script() { + const CODE: &str = "1 + 1"; + let _setup_guard = setup(); + let code_cache = { + let isolate = &mut v8::Isolate::new(Default::default()); + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let code = v8::String::new(scope, CODE).unwrap(); + let source = v8::script_compiler::Source::new(code, None); + let script = v8::script_compiler::compile_unbound_script( + scope, + source, + v8::script_compiler::CompileOptions::EagerCompile, + v8::script_compiler::NoCacheReason::NoReason, + ) + .unwrap(); + script.create_code_cache().unwrap().to_vec() + }; + + let isolate = &mut v8::Isolate::new(Default::default()); + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let code = v8::String::new(scope, CODE).unwrap(); + let source = v8::script_compiler::Source::new_with_cached_data( + code, + None, + v8::CachedData::new(&code_cache), + ); + let script = v8::script_compiler::compile( + scope, + source, + v8::script_compiler::CompileOptions::ConsumeCodeCache, + v8::script_compiler::NoCacheReason::NoReason, + ) + .unwrap(); + let ret = script.run(scope).unwrap(); + assert_eq!(ret.uint32_value(scope).unwrap(), 2); +}