summaryrefslogtreecommitdiff
path: root/ext/node/ops/vm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/ops/vm.rs')
-rw-r--r--ext/node/ops/vm.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/ext/node/ops/vm.rs b/ext/node/ops/vm.rs
new file mode 100644
index 000000000..f18038f8f
--- /dev/null
+++ b/ext/node/ops/vm.rs
@@ -0,0 +1,138 @@
+// 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<v8::String>,
+ ) -> Result<Self, AnyError> {
+ Ok(Self {
+ inner: i::ContextifyScript::new(scope, source)?,
+ })
+ }
+
+ fn run_in_this_context<'s>(
+ &self,
+ scope: &'s mut v8::HandleScope,
+ ) -> Result<v8::Local<'s, v8::Value>, 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<v8::Local<'s, v8::Value>, 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<v8::Local<'a, v8::Object>, 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<v8::Local<'a, v8::Value>, 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<v8::Local<'a, v8::Value>, AnyError> {
+ script.run_in_this_context(scope)
+}
+
+#[op2]
+pub fn op_vm_create_context(
+ scope: &mut v8::HandleScope,
+ sandbox_obj: v8::Local<v8::Object>,
+) {
+ // 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<v8::Value>,
+) -> 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());
+ }
+}