Skip to content

Commit

Permalink
Fix cross-realm construction bugs (#2786)
Browse files Browse the repository at this point in the history
This Pull Request fixes test [`assert-throws-same-realm.js`](https://github.com/tc39/test262/blob/eb44f67274bf3896fbec8814f81dd2ae02236686/test/harness/assert-throws-same-realm.js).

It changes the following:

- Handles global variables through the global object, instead of the `context`.
- Adds an `active_function` field to the vm, which is used as the `NewTarget` when certain builtins aren't called with `new`.
- Adds a `realm_intrinsics` field to `Function`.
  • Loading branch information
jedel1043 committed Apr 10, 2023
1 parent 928d67b commit 34d6b93
Show file tree
Hide file tree
Showing 68 changed files with 1,069 additions and 1,006 deletions.
21 changes: 3 additions & 18 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,9 @@
"program": "${workspaceFolder}/target/debug/boa.exe"
},
"program": "${workspaceFolder}/target/debug/boa",
"args": ["${workspaceFolder}/tests/js/test.js"],
"sourceLanguages": ["rust"]
},
{
"type": "lldb",
"request": "launch",
"name": "Launch (VM)",
"cargo": {
"args": [
"run",
"--manifest-path",
"./boa_cli/Cargo.toml",
"--features",
"vm"
]
},
"args": ["-t", "${workspaceFolder}/tests/js/test.js"],
"sourceLanguages": ["rust"]
"args": ["${workspaceFolder}/tests/js/test.js", "--debug-object"],
"sourceLanguages": ["rust"],
"preLaunchTask": "Cargo Build"
}
]
}
10 changes: 10 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "process",
"label": "Cargo Build",
"command": "cargo",
"args": ["build"],
"group": "build",
"presentation": {
"clear": true
}
},
{
"type": "process",
"label": "Cargo Run",
Expand Down
43 changes: 9 additions & 34 deletions boa_cli/src/debug/function.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use boa_engine::{
builtins::function::Function,
object::ObjectInitializer,
vm::flowgraph::{Direction, Graph},
Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction,
Expand Down Expand Up @@ -87,17 +86,9 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> Js
.into());
};

let code = match function {
Function::Ordinary { code, .. }
| Function::Async { code, .. }
| Function::Generator { code, .. }
| Function::AsyncGenerator { code, .. } => code,
Function::Native { .. } => {
return Err(JsNativeError::typ()
.with_message("native functions do not have bytecode")
.into())
}
};
let code = function.codeblock().ok_or_else(|| {
JsNativeError::typ().with_message("native functions do not have bytecode")
})?;

let mut graph = Graph::new(direction);
code.to_graph(context.interner(), graph.subgraph(String::default()));
Expand Down Expand Up @@ -127,17 +118,9 @@ fn bytecode(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> JsResul
.with_message("expected function object")
.into());
};
let code = match function {
Function::Ordinary { code, .. }
| Function::Async { code, .. }
| Function::Generator { code, .. }
| Function::AsyncGenerator { code, .. } => code,
Function::Native { .. } => {
return Err(JsNativeError::typ()
.with_message("native functions do not have bytecode")
.into())
}
};
let code = function.codeblock().ok_or_else(|| {
JsNativeError::typ().with_message("native functions do not have bytecode")
})?;

Ok(code.to_interned_string(context.interner()).into())
}
Expand All @@ -149,17 +132,9 @@ fn set_trace_flag_in_function_object(object: &JsObject, value: bool) -> JsResult
.with_message("expected function object")
.into());
};
let code = match function {
Function::Ordinary { code, .. }
| Function::Async { code, .. }
| Function::Generator { code, .. }
| Function::AsyncGenerator { code, .. } => code,
Function::Native { .. } => {
return Err(JsNativeError::typ()
.with_message("native functions do not have bytecode")
.into())
}
};
let code = function.codeblock().ok_or_else(|| {
JsNativeError::typ().with_message("native functions do not have bytecode")
})?;
code.set_trace(value);
Ok(())
}
Expand Down
19 changes: 14 additions & 5 deletions boa_cli/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ mod function;
mod gc;
mod object;
mod optimizer;
mod realm;

fn create_boa_object(context: &mut Context<'_>) -> JsObject {
let function_module = function::create_object(context);
let object_module = object::create_object(context);
let optimizer_module = optimizer::create_object(context);
let gc_module = gc::create_object(context);
let realm_module = realm::create_object(context);

ObjectInitializer::new(context)
.property(
Expand All @@ -35,14 +37,21 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject {
gc_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"realm",
realm_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build()
}

pub(crate) fn init_boa_debug_object(context: &mut Context<'_>) {
let boa_object = create_boa_object(context);
context.register_global_property(
"$boa",
boa_object,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
);
context
.register_global_property(
"$boa",
boa_object,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.expect("cannot fail with the default object");
}
14 changes: 14 additions & 0 deletions boa_cli/src/debug/realm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use boa_engine::{object::ObjectInitializer, Context, JsObject, JsResult, JsValue, NativeFunction};

/// Creates a new ECMAScript Realm and returns the global object of the realm.
fn create(_: &JsValue, _: &[JsValue], _: &mut Context<'_>) -> JsResult<JsValue> {
let context = &mut Context::default();

Ok(context.global_object().into())
}

pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
ObjectInitializer::new(context)
.function(NativeFunction::from_fn_ptr(create), "create", 0)
.build()
}
16 changes: 15 additions & 1 deletion boa_engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ impl BuiltInConstructor for Array {
context: &mut Context<'_>,
) -> JsResult<JsValue> {
// If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().array().constructor())
.into()
} else {
new_target.clone()
};

// 2. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%").
let prototype =
get_prototype_from_constructor(new_target, StandardConstructors::array, context)?;
Expand Down Expand Up @@ -358,9 +369,12 @@ impl Array {
// 4. If IsConstructor(C) is true, then
if let Some(c) = c.as_constructor() {
// a. Let thisRealm be the current Realm Record.
let this_realm = &context.intrinsics().clone();
// b. Let realmC be ? GetFunctionRealm(C).
let realm_c = &c.get_function_realm(context)?;

// c. If thisRealm and realmC are not the same Realm Record, then
if *c == context.intrinsics().constructors().array().constructor {
if this_realm != realm_c && *c == realm_c.constructors().array().constructor() {
// i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined.
// Note: fast path to step 6.
return Self::array_create(length, None, context);
Expand Down
18 changes: 15 additions & 3 deletions boa_engine/src/builtins/async_function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction
use crate::{
builtins::BuiltInObject,
builtins::{function::BuiltInFunctionObject, BuiltInObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
property::Attribute,
symbol::JsSymbol,
Expand Down Expand Up @@ -63,8 +63,20 @@ impl BuiltInConstructor for AsyncFunction {
args: &[JsValue],
context: &mut Context<'_>,
) -> JsResult<JsValue> {
crate::builtins::function::BuiltInFunctionObject::create_dynamic_function(
new_target, args, true, false, context,
let active_function = context.vm.active_function.clone().unwrap_or_else(|| {
context
.intrinsics()
.constructors()
.generator_function()
.constructor()
});
BuiltInFunctionObject::create_dynamic_function(
active_function,
new_target,
args,
true,
false,
context,
)
.map(Into::into)
}
Expand Down
Loading

0 comments on commit 34d6b93

Please sign in to comment.