// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::op2; use deno_core::v8; use super::vm_internal as i; pub struct Script { inner: i::ContextifyScript, } impl Script { fn new( scope: &mut v8::HandleScope, source: v8::Local, ) -> Result { Ok(Self { inner: i::ContextifyScript::new(scope, source)?, }) } fn run_in_this_context<'s>( &self, scope: &'s mut v8::HandleScope, ) -> Result, AnyError> { let context = scope.get_current_context(); let context_scope = &mut v8::ContextScope::new(scope, context); let mut scope = v8::EscapableHandleScope::new(context_scope); let result = self .inner .eval_machine(&mut scope, context) .unwrap_or_else(|| v8::undefined(&mut scope).into()); Ok(scope.escape(result)) } fn run_in_context<'s>( &self, scope: &mut v8::HandleScope<'s>, sandbox: v8::Local<'s, v8::Value>, ) -> Result, AnyError> { let context = if let Ok(sandbox_obj) = sandbox.try_into() { let context = i::ContextifyContext::from_sandbox_obj(scope, sandbox_obj) .ok_or_else(|| type_error("Invalid sandbox object"))?; context.context(scope) } else { scope.get_current_context() }; let context_scope = &mut v8::ContextScope::new(scope, context); let mut scope = v8::EscapableHandleScope::new(context_scope); let result = self .inner .eval_machine(&mut scope, context) .unwrap_or_else(|| v8::undefined(&mut scope).into()); Ok(scope.escape(result)) } } #[op2] pub fn op_vm_create_script<'a>( scope: &mut v8::HandleScope<'a>, source: v8::Local<'a, v8::String>, ) -> Result, AnyError> { let script = Script::new(scope, source)?; Ok(deno_core::cppgc::make_cppgc_object(scope, script)) } #[op2(reentrant)] pub fn op_vm_script_run_in_context<'a>( scope: &mut v8::HandleScope<'a>, #[cppgc] script: &Script, sandbox: v8::Local<'a, v8::Value>, ) -> Result, AnyError> { script.run_in_context(scope, sandbox) } #[op2(reentrant)] pub fn op_vm_script_run_in_this_context<'a>( scope: &'a mut v8::HandleScope, #[cppgc] script: &Script, ) -> Result, AnyError> { script.run_in_this_context(scope) } #[op2] pub fn op_vm_create_context( scope: &mut v8::HandleScope, sandbox_obj: v8::Local, ) { // Don't allow contextifying a sandbox multiple times. assert!(!i::ContextifyContext::is_contextify_context( scope, sandbox_obj )); i::ContextifyContext::attach(scope, sandbox_obj); } #[op2] pub fn op_vm_is_context( scope: &mut v8::HandleScope, sandbox_obj: v8::Local, ) -> bool { sandbox_obj .try_into() .map(|sandbox_obj| { i::ContextifyContext::is_contextify_context(scope, sandbox_obj) }) .unwrap_or(false) } #[cfg(test)] mod tests { use super::*; use deno_core::v8; #[test] fn test_run_in_this_context() { let platform = v8::new_default_platform(0, false).make_shared(); v8::V8::initialize_platform(platform); v8::V8::initialize(); 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 source = v8::String::new(scope, "1 + 2").unwrap(); let script = Script::new(scope, source).unwrap(); let result = script.run_in_this_context(scope).unwrap(); assert!(result.is_number()); } }