Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- main
- releases/**
- dev/oscars-gc

permissions:
contents: read
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ on:
branches:
- main
- releases/**
- dev/oscars-gc
push:
branches:
- main
- releases/**
- dev/oscars-gc
merge_group:
types: [checks_requested]
workflow_dispatch:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test262.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- main
- releases/**
- dev/oscars-gc

permissions:
contents: read
Expand All @@ -15,6 +16,7 @@ concurrency:

jobs:
run_test262:
if: ${{ github.base_ref != 'dev/oscars-gc' }}
name: Run the test262 test suite
runs-on: ubuntu-latest
timeout-minutes: 60
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/webassembly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ on:
branches:
- main
- releases/**
- dev/oscars-gc
push:
branches:
- main
- releases/**
- dev/oscars-gc
merge_group:
types: [checks_requested]

Expand Down
11 changes: 9 additions & 2 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ num-integer = "0.1.46"
ryu-js = "1.0.2"
tap = "1.0.1"
thiserror = { version = "2.0.18", default-features = false }
typeid = "1.0.3"
dashmap = "6.2.1"
num_enum = "0.7.6"
itertools = { version = "0.15.0", default-features = false }
Expand Down Expand Up @@ -267,3 +268,6 @@ complexity = { level = "warn", priority = -1 }
perf = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }

[patch."https://github.com/boa-dev/boa.git"]
boa_string = { path = "core/string" }

1 change: 1 addition & 0 deletions core/engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ embedded_lz4 = ["boa_macros/embedded_lz4", "lz4_flex"]
jsvalue-enum = []
deser = ["boa_interner/serde", "boa_ast/serde"]
either = ["dep:either", "boa_gc/either"]
oscars_backend = ["boa_gc/oscars_backend", "boa_string/oscars_backend"]

# Enables the `Intl` builtin object and bundles a default ICU4X data provider.
# Prefer this over `intl` if you just want to enable `Intl` without dealing with the
Expand Down
14 changes: 7 additions & 7 deletions core/engine/src/builtins/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,8 @@ impl Eval {

compiler.compile_statement_list(body.statements(), true, false);

let code_block = Gc::new(
&unsafe { boa_gc::MutationContext::dummy() },
compiler.finish(),
);
let finished = compiler.finish();
let code_block = context.alloc(finished);

// Strict calls don't need extensions, since all strict eval calls push a new
// function environment before evaluating.
Expand All @@ -350,9 +348,11 @@ impl Eval {
{
let frame = context.vm.frame_mut();
let global = frame.realm.environment();
frame
.environments
.push_lexical(lexical_scope.num_bindings_non_local(), global);
frame.environments.push_lexical(
lexical_scope.num_bindings_non_local(),
global,
unsafe { boa_gc::MutationContext::global() },
);
}

context
Expand Down
26 changes: 9 additions & 17 deletions core/engine/src/builtins/finalization_registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,7 @@ impl BuiltInConstructor for FinalizationRegistry {
},
);

let weak_registry = WeakGc::new(
&unsafe { boa_gc::MutationContext::dummy() },
registry.inner(),
);
let weak_registry = WeakGc::new(context.gc_collector(), registry.inner());

{
async fn inner_cleanup(
Expand All @@ -174,7 +171,7 @@ impl BuiltInConstructor for FinalizationRegistry {
};

let Some(registry) = weak_registry
.upgrade(&unsafe { boa_gc::MutationContext::dummy() })
.upgrade(&unsafe { boa_gc::MutationContext::global() })
.map(JsObject::from_inner)
else {
return Ok(JsValue::undefined());
Expand Down Expand Up @@ -205,7 +202,7 @@ impl FinalizationRegistry {
/// [`FinalizationRegistry.prototype.register ( target, heldValue [ , unregisterToken ] )`][spec]
///
/// [spec]: https://tc39.es/ecma262/sec-finalization-registry.prototype.register
fn register(this: &JsValue, args: &[JsValue], _context: &mut Context) -> JsResult<JsValue> {
fn register(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. Let finalizationRegistry be the this value.
// 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
let this = this.as_object();
Expand Down Expand Up @@ -257,10 +254,7 @@ impl FinalizationRegistry {
//
// TODO: support Symbols
let unregister_token = match unregister_token.variant() {
JsVariant::Object(obj) => Some(WeakGc::new(
&unsafe { boa_gc::MutationContext::dummy() },
obj.inner(),
)),
JsVariant::Object(obj) => Some(WeakGc::new(context.gc_collector(), obj.inner())),
// b. Set unregisterToken to empty.
JsVariant::Undefined => None,
// a. If unregisterToken is not undefined, throw a TypeError exception.
Expand All @@ -275,7 +269,7 @@ impl FinalizationRegistry {
// 6. Let cell be the Record { [[WeakRefTarget]]: target, [[HeldValue]]: heldValue, [[UnregisterToken]]: unregisterToken }.
let cell = RegistryCell {
target: Ephemeron::new(
&unsafe { boa_gc::MutationContext::dummy() },
context.gc_collector(),
target_obj.inner(),
CleanupSignaler(Cell::new(Some(
registry.cleanup_notifier.clone().downgrade(),
Expand All @@ -295,7 +289,7 @@ impl FinalizationRegistry {
/// [`FinalizationRegistry.prototype.unregister ( unregisterToken )`][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-finalization-registry.prototype.unregister
fn unregister(this: &JsValue, args: &[JsValue], _context: &mut Context) -> JsResult<JsValue> {
fn unregister(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. Let finalizationRegistry be the this value.
// 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
let this = this.as_object();
Expand Down Expand Up @@ -338,19 +332,17 @@ impl FinalizationRegistry {

// a. If cell.[[UnregisterToken]] is not empty and SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then
if let Some(tok) = cell.unregister_token.as_ref()
&& let Some(tok) = tok.upgrade(&unsafe { boa_gc::MutationContext::dummy() })
&& let Some(tok) = tok.upgrade(context.gc_collector())
&& Gc::ptr_eq(&tok, unregister_token)
{
// i. Remove cell from finalizationRegistry.[[Cells]].
let cell = registry.cells.swap_remove(i);
let _key = cell
.target
.key(&unsafe { boa_gc::MutationContext::dummy() });
let _key = cell.target.key(context.gc_collector());

// TODO: it might be better to add a special ref for the value that
// also preserves the original key instead.
cell.target
.value(&unsafe { boa_gc::MutationContext::dummy() })
.value(context.gc_collector())
.and_then(|v| v.0.take());

// ii. Set removed to true.
Expand Down
1 change: 1 addition & 0 deletions core/engine/src/builtins/finalization_registry/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(not(feature = "oscars_backend"))]
mod miri {

use indoc::indoc;
Expand Down
4 changes: 3 additions & 1 deletion core/engine/src/builtins/function/arguments.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::trivially_copy_pass_by_ref)]
#![allow(clippy::needless_pass_by_value)]
use crate::{
Context, JsData, JsExpect, JsResult, JsValue,
bytecompiler::ToJsString,
Expand Down Expand Up @@ -124,7 +126,7 @@ impl MappedArguments {
.get(index as usize)
.copied()
.flatten()?;
self.environment.get(binding_index)
(*self.environment).get(binding_index)
}

/// Set the value of the binding at the given index in the function environment.
Expand Down
10 changes: 8 additions & 2 deletions core/engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,9 @@ pub(crate) fn function_call(
if has_binding_identifier {
let frame = context.vm.frame_mut();
let global = frame.realm.environment();
let index = frame.environments.push_lexical(1, global);
let index = frame
.environments
.push_lexical(1, global, unsafe { boa_gc::MutationContext::global() });
frame.environments.put_lexical_value(
BindingLocatorScope::Stack(index),
0,
Expand All @@ -1091,6 +1093,7 @@ pub(crate) fn function_call(
scope,
FunctionSlots::new(this, function_object.clone(), None),
global,
unsafe { boa_gc::MutationContext::global() },
);
}

Expand Down Expand Up @@ -1181,7 +1184,9 @@ fn function_construct(
if has_binding_identifier {
let frame = context.vm.frame_mut();
let global = frame.realm.environment();
let index = frame.environments.push_lexical(1, global);
let index = frame
.environments
.push_lexical(1, global, unsafe { boa_gc::MutationContext::global() });
frame.environments.put_lexical_value(
BindingLocatorScope::Stack(index),
0,
Expand Down Expand Up @@ -1210,6 +1215,7 @@ fn function_construct(
),
),
global,
unsafe { boa_gc::MutationContext::global() },
);
}

Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub(crate) enum GeneratorState {
// Need to manually implement, since `Trace` adds a `Drop` impl which disallows destructuring.
unsafe impl Trace for GeneratorState {
custom_trace!(this, mark, {
match &this {
match this {
Self::SuspendedStart { context } | Self::SuspendedYield { context } => mark(context),
Self::Executing | Self::Completed => {}
}
Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/intl/list_format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl ListFormat {
part: writeable::Part,
mut f: impl FnMut(&mut Self::SubPartsWrite) -> core::fmt::Result,
) -> core::fmt::Result {
assert!(part.category == "list");
assert_eq!(part.category, "list");
let mut string = WriteString(String::new());
f(&mut string)?;
if !string.0.is_empty() {
Expand Down
13 changes: 9 additions & 4 deletions core/engine/src/builtins/intl/locale/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,14 +349,17 @@ impl Locale {
// 1. Let loc be the this value.
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
let object = this.as_object();
// Under `oscars_backend`, `downcast_ref` returns `GcRef<'_, Locale>`.
// Deref through the guard before cloning to get an owned `icu_locale::Locale`.
// This is required because `GcRef<'_, Locale>` doesn't implement `NativeObject`.
let mut loc = object
.as_ref()
.and_then(|o| o.downcast_ref::<icu_locale::Locale>())
.ok_or_else(|| {
JsNativeError::typ()
.with_message("`Locale.maximize` can only be called on a `Locale` object")
})?
.clone();
})
.map(|r| (*r).clone())?;

// 3. Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
context
Expand Down Expand Up @@ -387,15 +390,17 @@ impl Locale {
// 1. Let loc be the this value.
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
let object = this.as_object();
// Under `oscars_backend`, `downcast_ref` returns `GcRef<'_, Locale>`.
// Deref through the guard before cloning to get an owned `icu_locale::Locale`.
let mut loc = object
.as_ref()
.and_then(|o| o.downcast_ref::<icu_locale::Locale>())
.ok_or_else(|| {
JsNativeError::typ().with_message(
"`Locale.prototype.minimize` can only be called on a `Locale` object",
)
})?
.clone();
})
.map(|r| (*r).clone())?;

// 3. Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
context
Expand Down
4 changes: 3 additions & 1 deletion core/engine/src/builtins/intl/locale/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ pub(crate) fn locale_from_value(tag: &JsValue, context: &mut Context) -> JsResul
if let Some(tag) = object.as_ref().and_then(|obj| obj.downcast_ref::<Locale>()) {
// 1. Let tag be kValue.[[Locale]].
// No need to canonicalize since all `Locale` objects should already be canonicalized.
return Ok(tag.clone());
// Under `oscars_backend`, `downcast_ref` returns `GcRef<'_, Locale>`.
// Deref through the guard before cloning to clone the `Locale` value, not the wrapper.
return Ok((*tag).clone());
}

// iv. Else,
Expand Down
11 changes: 6 additions & 5 deletions core/engine/src/builtins/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,8 @@ impl Json {
SourcePath::Json,
);
compiler.compile_statement_list(script.statements(), true, false);
Gc::new(
&unsafe { boa_gc::MutationContext::dummy() },
compiler.finish(),
)
let finished = compiler.finish();
context.alloc(finished)
};

let realm = context.realm().clone();
Expand Down Expand Up @@ -815,7 +813,10 @@ impl Json {
// d. Else if value has a [[BigIntData]] internal slot, then
else if let Some(bigint) = obj.downcast_ref::<JsBigInt>() {
// i. Set value to value.[[BigIntData]].
value = bigint.clone().into();
// SAFETY: Under oscars_backend, `downcast_ref` returns a `GcRef<'_, JsBigInt>`.
// We must deref through the guard before calling `.clone()` so that we clone
// the inner `JsBigInt`, not the `GcRef` wrapper.
value = (*bigint).clone().into();
}
// e. Else if value has a [[IsRawJSON]] internal slot, then
else if obj.is::<RawJson>() {
Expand Down
Loading
Loading