Skip to content

Commit 69b5fba

Browse files
committed
fix(ext/node): node:vm contexts (denoland#23202)
Implement contextified objects in `node:vm` Fixes denoland#23186 Fixes denoland#22395 Fixes denoland#20607 Fixes denoland#18299 Fixes denoland#19395 Fixes denoland#18315 Fixes denoland#18319 Fixes denoland#23183
1 parent 884eb01 commit 69b5fba

File tree

6 files changed

+849
-37
lines changed

6 files changed

+849
-37
lines changed

ext/node/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,11 @@ deno_core::extension!(deno_node,
260260
ops::winerror::op_node_sys_to_uv_error,
261261
ops::v8::op_v8_cached_data_version_tag,
262262
ops::v8::op_v8_get_heap_statistics,
263-
ops::v8::op_vm_run_in_new_context,
263+
ops::vm::op_vm_create_script,
264+
ops::vm::op_vm_create_context,
265+
ops::vm::op_vm_script_run_in_context,
266+
ops::vm::op_vm_script_run_in_this_context,
267+
ops::vm::op_vm_is_context,
264268
ops::idna::op_node_idna_domain_to_ascii,
265269
ops::idna::op_node_idna_domain_to_unicode,
266270
ops::idna::op_node_idna_punycode_to_ascii,

ext/node/ops/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub mod process;
1111
pub mod require;
1212
pub mod util;
1313
pub mod v8;
14+
pub mod vm;
15+
mod vm_internal;
1416
pub mod winerror;
1517
pub mod worker_threads;
1618
pub mod zlib;

ext/node/ops/vm.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2+
3+
use deno_core::error::type_error;
4+
use deno_core::error::AnyError;
5+
use deno_core::op2;
6+
use deno_core::v8;
7+
8+
use super::vm_internal as i;
9+
10+
pub struct Script {
11+
inner: i::ContextifyScript,
12+
}
13+
14+
impl Script {
15+
fn new(
16+
scope: &mut v8::HandleScope,
17+
source: v8::Local<v8::String>,
18+
) -> Result<Self, AnyError> {
19+
Ok(Self {
20+
inner: i::ContextifyScript::new(scope, source)?,
21+
})
22+
}
23+
24+
fn run_in_this_context<'s>(
25+
&self,
26+
scope: &'s mut v8::HandleScope,
27+
) -> Result<v8::Local<'s, v8::Value>, AnyError> {
28+
let context = scope.get_current_context();
29+
30+
let context_scope = &mut v8::ContextScope::new(scope, context);
31+
let mut scope = v8::EscapableHandleScope::new(context_scope);
32+
let result = self
33+
.inner
34+
.eval_machine(&mut scope, context)
35+
.unwrap_or_else(|| v8::undefined(&mut scope).into());
36+
Ok(scope.escape(result))
37+
}
38+
39+
fn run_in_context<'s>(
40+
&self,
41+
scope: &mut v8::HandleScope<'s>,
42+
sandbox: v8::Local<'s, v8::Value>,
43+
) -> Result<v8::Local<'s, v8::Value>, AnyError> {
44+
let context = if let Ok(sandbox_obj) = sandbox.try_into() {
45+
let context = i::ContextifyContext::from_sandbox_obj(scope, sandbox_obj)
46+
.ok_or_else(|| type_error("Invalid sandbox object"))?;
47+
context.context(scope)
48+
} else {
49+
scope.get_current_context()
50+
};
51+
52+
let context_scope = &mut v8::ContextScope::new(scope, context);
53+
let mut scope = v8::EscapableHandleScope::new(context_scope);
54+
let result = self
55+
.inner
56+
.eval_machine(&mut scope, context)
57+
.unwrap_or_else(|| v8::undefined(&mut scope).into());
58+
Ok(scope.escape(result))
59+
}
60+
}
61+
62+
#[op2]
63+
pub fn op_vm_create_script<'a>(
64+
scope: &mut v8::HandleScope<'a>,
65+
source: v8::Local<'a, v8::String>,
66+
) -> Result<v8::Local<'a, v8::Object>, AnyError> {
67+
let script = Script::new(scope, source)?;
68+
Ok(deno_core::cppgc::make_cppgc_object(scope, script))
69+
}
70+
71+
#[op2(reentrant)]
72+
pub fn op_vm_script_run_in_context<'a>(
73+
scope: &mut v8::HandleScope<'a>,
74+
#[cppgc] script: &Script,
75+
sandbox: v8::Local<'a, v8::Value>,
76+
) -> Result<v8::Local<'a, v8::Value>, AnyError> {
77+
script.run_in_context(scope, sandbox)
78+
}
79+
80+
#[op2(reentrant)]
81+
pub fn op_vm_script_run_in_this_context<'a>(
82+
scope: &'a mut v8::HandleScope,
83+
#[cppgc] script: &Script,
84+
) -> Result<v8::Local<'a, v8::Value>, AnyError> {
85+
script.run_in_this_context(scope)
86+
}
87+
88+
#[op2]
89+
pub fn op_vm_create_context(
90+
scope: &mut v8::HandleScope,
91+
sandbox_obj: v8::Local<v8::Object>,
92+
) {
93+
// Don't allow contextifying a sandbox multiple times.
94+
assert!(!i::ContextifyContext::is_contextify_context(
95+
scope,
96+
sandbox_obj
97+
));
98+
99+
i::ContextifyContext::attach(scope, sandbox_obj);
100+
}
101+
102+
#[op2]
103+
pub fn op_vm_is_context(
104+
scope: &mut v8::HandleScope,
105+
sandbox_obj: v8::Local<v8::Value>,
106+
) -> bool {
107+
sandbox_obj
108+
.try_into()
109+
.map(|sandbox_obj| {
110+
i::ContextifyContext::is_contextify_context(scope, sandbox_obj)
111+
})
112+
.unwrap_or(false)
113+
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::*;
118+
use deno_core::v8;
119+
120+
#[test]
121+
fn test_run_in_this_context() {
122+
let platform = v8::new_default_platform(0, false).make_shared();
123+
v8::V8::initialize_platform(platform);
124+
v8::V8::initialize();
125+
126+
let isolate = &mut v8::Isolate::new(Default::default());
127+
128+
let scope = &mut v8::HandleScope::new(isolate);
129+
let context = v8::Context::new(scope);
130+
let scope = &mut v8::ContextScope::new(scope, context);
131+
132+
let source = v8::String::new(scope, "1 + 2").unwrap();
133+
let script = Script::new(scope, source).unwrap();
134+
135+
let result = script.run_in_this_context(scope).unwrap();
136+
assert!(result.is_number());
137+
}
138+
}

0 commit comments

Comments
 (0)