Skip to content

Commit

Permalink
new global modes
Browse files Browse the repository at this point in the history
  • Loading branch information
devsnek committed Jul 29, 2024
1 parent 2de66e1 commit aeb7a51
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 119 deletions.
15 changes: 9 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ repository = "https://github.com/denoland/deno"

[workspace.dependencies]
deno_ast = { version = "=0.40.0", features = ["transpiling"] }
deno_core = { git = "https://github.com/denoland/deno_core.git", rev = "4fe63c9" }
deno_core = { version = "0.300.0" }

deno_bench_util = { version = "0.157.0", path = "./bench_util" }
deno_lockfile = "0.20.0"
Expand Down
15 changes: 14 additions & 1 deletion cli/module_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use crate::util::text_encoding::code_without_source_map;
use crate::util::text_encoding::source_map_from_code;
use crate::worker::ModuleLoaderAndSourceMapGetter;
use crate::worker::ModuleLoaderFactory;

use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
Expand Down Expand Up @@ -64,6 +63,7 @@ use deno_graph::Module;
use deno_graph::ModuleGraph;
use deno_graph::Resolution;
use deno_runtime::code_cache;
use deno_runtime::deno_node::get_host_defined_options;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::NodeResolutionMode;
Expand Down Expand Up @@ -724,6 +724,19 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
Ok(specifier)
}

fn get_host_defined_options<'s>(
&self,
scope: &mut deno_core::v8::HandleScope<'s>,
name: &str,
) -> Option<deno_core::v8::Local<'s, deno_core::v8::Data>> {
let name = deno_core::ModuleSpecifier::parse(name).ok()?;
if self.0.shared.node_resolver.in_npm_package(&name) {
Some(get_host_defined_options(scope))
} else {
None
}
}

fn load(
&self,
specifier: &ModuleSpecifier,
Expand Down
14 changes: 14 additions & 0 deletions cli/standalone/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use deno_core::ResolutionKind;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonDepValue;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::get_host_defined_options;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
Expand Down Expand Up @@ -267,6 +268,19 @@ impl ModuleLoader for EmbeddedModuleLoader {
}
}

fn get_host_defined_options<'s>(
&self,
scope: &mut deno_core::v8::HandleScope<'s>,
name: &str,
) -> Option<deno_core::v8::Local<'s, deno_core::v8::Data>> {
let name = deno_core::ModuleSpecifier::parse(name).ok()?;
if self.shared.node_resolver.in_npm_package(&name) {
Some(get_host_defined_options(scope))
} else {
None
}
}

fn load(
&self,
original_specifier: &ModuleSpecifier,
Expand Down
22 changes: 9 additions & 13 deletions ext/node/global.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use std::mem::MaybeUninit;

use deno_core::v8;
use deno_core::v8::GetPropertyNamesArgs;
use deno_core::v8::MapFnTo;

use crate::NodeResolverRc;

// NOTE(bartlomieju): somehow calling `.map_fn_to()` multiple times on a function
// returns two different pointers. That shouldn't be the case as `.map_fn_to()`
// creates a thin wrapper that is a pure function. @piscisaureus suggests it
Expand Down Expand Up @@ -239,19 +235,19 @@ fn is_managed_key(
}

fn current_mode(scope: &mut v8::HandleScope) -> Mode {
let Some(v8_string) =
v8::StackTrace::current_script_name_or_source_url(scope)
let Some(host_defined_options) = scope.get_current_host_defined_options()
else {
return Mode::Deno;
};
let op_state = deno_core::JsRuntime::op_state_from(scope);
let op_state = op_state.borrow();
let Some(node_resolver) = op_state.try_borrow::<NodeResolverRc>() else {
return Mode::Deno;
// SAFETY: host defined options must always be a PrimitiveArray in current V8.
let host_defined_options = unsafe {
v8::Local::<v8::PrimitiveArray>::cast_unchecked(host_defined_options)
};
let mut buffer = [MaybeUninit::uninit(); 2048];
let str = v8_string.to_rust_cow_lossy(scope, &mut buffer);
if str.starts_with("node:") || node_resolver.in_npm_package_with_cache(str) {
if host_defined_options.length() < 1 {
return Mode::Deno;
}
let is_node = host_defined_options.get(scope, 0).is_true();
if is_node {
Mode::Node
} else {
Mode::Deno
Expand Down
9 changes: 9 additions & 0 deletions ext/node/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,3 +836,12 @@ impl<'a> deno_package_json::fs::DenoPkgJsonFs for DenoPkgJsonFsAdapter<'a> {
.map_err(|err| err.into_io_error())
}
}

pub fn get_host_defined_options<'s>(
scope: &mut v8::HandleScope<'s>,
) -> v8::Local<'s, v8::Data> {
let host_defined_options = v8::PrimitiveArray::new(scope, 1);
let value = v8::Boolean::new(scope, true);
host_defined_options.set(scope, 0, value.into());
host_defined_options.into()
}
18 changes: 17 additions & 1 deletion ext/node/ops/vm_internal.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use crate::get_host_defined_options;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::v8;
Expand All @@ -19,7 +20,22 @@ impl ContextifyScript {
scope: &mut v8::HandleScope,
source_str: v8::Local<v8::String>,
) -> Result<Self, AnyError> {
let source = v8::script_compiler::Source::new(source_str, None);
let resource_name = v8::undefined(scope);
let host_defined_options = get_host_defined_options(scope);
let origin = v8::ScriptOrigin::new(
scope,
resource_name.into(),
0,
0,
false,
0,
None,
false,
false,
false,
Some(host_defined_options),
);
let source = v8::script_compiler::Source::new(source_str, Some(&origin));

let unbound_script = v8::script_compiler::compile_unbound_script(
scope,
Expand Down
30 changes: 25 additions & 5 deletions ext/node/polyfills/01_require.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,9 +976,14 @@ function wrapSafe(
filename,
content,
cjsModuleInstance,
format,
) {
const wrapper = Module.wrap(content);
const [f, err] = core.evalContext(wrapper, `file://${filename}`);
const [f, err] = core.evalContext(
wrapper,
url.pathToFileURL(filename).toString(),
[format !== "module"],
);
if (err) {
if (process.mainModule === cjsModuleInstance) {
enrichCJSError(err.thrown);
Expand All @@ -995,8 +1000,16 @@ function wrapSafe(
return f;
}

Module.prototype._compile = function (content, filename) {
const compiledWrapper = wrapSafe(filename, content, this);
Module.prototype._compile = function (content, filename, format) {
const compiledWrapper = wrapSafe(filename, content, this, format);

if (format === "module") {
// TODO: implement require esm
throw createRequireEsmError(
filename,
moduleParentCache.get(module)?.filename,
);
}

const dirname = pathDirname(filename);
const require = makeRequireFunction(this);
Expand Down Expand Up @@ -1053,17 +1066,24 @@ Module.prototype._compile = function (content, filename) {
Module._extensions[".js"] = function (module, filename) {
const content = op_require_read_file(filename);

let format;
if (StringPrototypeEndsWith(filename, ".js")) {
const pkg = op_require_read_closest_package_json(filename);
if (pkg && pkg.typ === "module") {
if (pkg?.typ === "module") {
// TODO: implement require esm
format = "module";
throw createRequireEsmError(
filename,
moduleParentCache.get(module)?.filename,
);
} else if (pkg?.type === "commonjs") {
format = "commonjs";
}
} else if (StringPrototypeEndsWith(filename, ".cjs")) {
format = "commonjs";
}

module._compile(content, filename);
module._compile(content, filename, format);
};

function createRequireEsmError(filename, parent) {
Expand Down
24 changes: 1 addition & 23 deletions ext/node_resolver/resolution.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;

Expand Down Expand Up @@ -138,38 +137,17 @@ pub type NodeResolverRc<TEnv> = crate::sync::MaybeArc<NodeResolver<TEnv>>;
pub struct NodeResolver<TEnv: NodeResolverEnv> {
env: TEnv,
npm_resolver: NpmResolverRc,
in_npm_package_cache: crate::sync::MaybeArcMutex<HashMap<String, bool>>,
}

impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
pub fn new(env: TEnv, npm_resolver: NpmResolverRc) -> Self {
Self {
env,
npm_resolver,
in_npm_package_cache: crate::sync::MaybeArcMutex::new(HashMap::new()),
}
Self { env, npm_resolver }
}

pub fn in_npm_package(&self, specifier: &Url) -> bool {
self.npm_resolver.in_npm_package(specifier)
}

pub fn in_npm_package_with_cache(&self, specifier: Cow<str>) -> bool {
let mut cache = self.in_npm_package_cache.lock();

if let Some(result) = cache.get(specifier.as_ref()) {
return *result;
}

let result = if let Ok(specifier) = Url::parse(&specifier) {
self.npm_resolver.in_npm_package(&specifier)
} else {
false
};
cache.insert(specifier.into_owned(), result);
result
}

/// This function is an implementation of `defaultResolve` in
/// `lib/internal/modules/esm/resolve.js` from Node.
pub fn resolve(
Expand Down
68 changes: 0 additions & 68 deletions ext/node_resolver/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,13 @@ pub use inner::*;
mod inner {
#![allow(clippy::disallowed_types)]

use std::ops::Deref;
use std::ops::DerefMut;
pub use std::sync::Arc as MaybeArc;

pub struct MaybeArcMutexGuard<'lock, T>(std::sync::MutexGuard<'lock, T>);

impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
type Target = std::sync::MutexGuard<'lock, T>;
fn deref(&self) -> &std::sync::MutexGuard<'lock, T> {
&self.0
}
}

impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
fn deref_mut(&mut self) -> &mut std::sync::MutexGuard<'lock, T> {
&mut self.0
}
}

#[derive(Debug)]
pub struct MaybeArcMutex<T>(std::sync::Arc<std::sync::Mutex<T>>);
impl<T> MaybeArcMutex<T> {
pub fn new(val: T) -> Self {
Self(std::sync::Arc::new(std::sync::Mutex::new(val)))
}
}

impl<'lock, T> MaybeArcMutex<T> {
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
MaybeArcMutexGuard(self.0.lock().unwrap())
}
}

pub use core::marker::Send as MaybeSend;
pub use core::marker::Sync as MaybeSync;
}

#[cfg(not(feature = "sync"))]
mod inner {
use std::ops::Deref;
use std::ops::DerefMut;

pub use std::rc::Rc as MaybeArc;

pub struct MaybeArcMutexGuard<'lock, T>(std::cell::RefMut<'lock, T>);

impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
type Target = std::cell::RefMut<'lock, T>;
fn deref(&self) -> &std::cell::RefMut<'lock, T> {
&self.0
}
}

impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
fn deref_mut(&mut self) -> &mut std::cell::RefMut<'lock, T> {
&mut self.0
}
}

#[derive(Debug)]
pub struct MaybeArcMutex<T>(std::rc::Rc<std::cell::RefCell<T>>);
impl<T> MaybeArcMutex<T> {
pub fn new(val: T) -> Self {
Self(std::rc::Rc::new(std::cell::RefCell::new(val)))
}
}

impl<'lock, T> MaybeArcMutex<T> {
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
MaybeArcMutexGuard(self.0.borrow_mut())
}
}

pub trait MaybeSync {}
impl<T> MaybeSync for T where T: ?Sized {}
pub trait MaybeSend {}
impl<T> MaybeSend for T where T: ?Sized {}
}
1 change: 0 additions & 1 deletion tests/node_compat/test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ let knownGlobals = [
queueMicrotask,
removeEventListener,
reportError,
self,
sessionStorage,
setImmediate,
];
Expand Down

0 comments on commit aeb7a51

Please sign in to comment.