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 Cargo.lock

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

13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ members = [

exclude = [
"tests/fuzz", # Does weird things on Windows tests
"tests/src", # Just a hack to have fuzz inside tests
"tests/wpt", # Should not run WPT by default.
"tests/src", # Just a hack to have fuzz inside tests
"tests/wpt", # Should not run WPT by default.
]

[workspace.package]
Expand Down Expand Up @@ -75,7 +75,9 @@ phf = { version = "0.13.1", default-features = false }
pollster = "0.4.0"
regex = "1.12.3"
regress = { version = "0.11.0", features = ["utf16"] }
reqwest = { version = "0.13.2", default-features = false, features = ["rustls-no-provider"] }
reqwest = { version = "0.13.2", default-features = false, features = [
"rustls-no-provider",
] }
rustls = { version = "0.23.37", default-features = false, features = ["ring"] }
rustc-hash = { version = "2.1.1", default-features = false }
serde_json = "1.0.149"
Expand Down Expand Up @@ -129,7 +131,9 @@ cfg-if = "1.0.4"
either = "1.15.0"
sys-locale = "0.3.2"
timezone_provider = { version = "0.2.0" }
temporal_rs = { version = "0.2.0", default-features = false, features = ["float64_representable_durations"] }
temporal_rs = { version = "0.2.0", default-features = false, features = [
"float64_representable_durations",
] }
web-time = "1.1.0"
criterion = "0.8.1"
float-cmp = "0.10.0"
Expand All @@ -146,6 +150,7 @@ temp-env = "0.3.6"
strum = { version = "0.28", features = ["derive"] }
husky-rs = "0.3.2"
async-channel = "2.5.0"
rustversion = "1"

# ICU4X

Expand Down
22 changes: 17 additions & 5 deletions core/engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ trace = ["js"]
annex-b = ["boa_ast/annex-b", "boa_parser/annex-b"]

# Enable Boa's Temporal proposal implementation
temporal = ["dep:icu_calendar", "dep:temporal_rs", "dep:timezone_provider", "timezone_provider/experimental_tzif"]
temporal = [
"dep:icu_calendar",
"dep:temporal_rs",
"dep:timezone_provider",
"timezone_provider/experimental_tzif",
]

#Enable access to host system timezone
system-time-zone = ["dep:iana-time-zone"]
Expand All @@ -91,6 +96,10 @@ xsum = ["dep:xsum"]
# Native Backtraces
native-backtrace = []

# Enable support for tail call optimization. Requires nightly
# See https://github.com/rust-lang/rust/issues/112788 and https://github.com/rust-lang/rust/issues/151401
tailcall = []

[dependencies]
tag_ptr.workspace = true
boa_interner.workspace = true
Expand Down Expand Up @@ -123,7 +132,9 @@ thiserror.workspace = true
dashmap.workspace = true
num_enum.workspace = true
thin-vec.workspace = true
itertools = { workspace = true, default-features = false, features = ["use_alloc"] }
itertools = { workspace = true, default-features = false, features = [
"use_alloc",
] }
icu_normalizer = { workspace = true, features = [
"compiled_data",
"utf16_iter",
Expand Down Expand Up @@ -180,9 +191,7 @@ icu_decimal = { workspace = true, default-features = false, features = [
writeable = { workspace = true, optional = true }
yoke = { workspace = true, optional = true }
zerofrom = { workspace = true, optional = true }
fixed_decimal = { workspace = true, features = [
"ryu",
], optional = true }
fixed_decimal = { workspace = true, features = ["ryu"], optional = true }
tinystr = { workspace = true, optional = true }

# temporal deps
Expand All @@ -203,6 +212,9 @@ textwrap.workspace = true
test-case.workspace = true
husky-rs.workspace = true

[build-dependencies]
rustversion.workspace = true

[target.x86_64-unknown-linux-gnu.dev-dependencies]
jemallocator.workspace = true

Expand Down
10 changes: 10 additions & 0 deletions core/engine/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Build script for the `boa_engine` crate to detect if the toolchain is nightly.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
// Tell rustc that `cfg(boa_nightly)` is intentional
println!("cargo:rustc-check-cfg=cfg(boa_nightly)");

if rustversion::cfg!(since(2026 - 01 - 26)) {
println!("cargo:rustc-cfg=boa_nightly");
}
}
2 changes: 2 additions & 0 deletions core/engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,8 @@ impl<'ctx> ByteCompiler<'ctx> {
debug_id: CodeBlock::get_next_codeblock_id(),
#[cfg(feature = "trace")]
traced: Cell::new(false),
#[cfg(all(feature = "trace", all(feature = "tailcall", boa_nightly)))]
last_trace_time: Cell::new(None),
}
}

Expand Down
3 changes: 3 additions & 0 deletions core/engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
html_logo_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo_black.svg",
html_favicon_url = "https://raw.githubusercontent.com/boa-dev/boa/main/assets/logo_black.svg"
)]
#![cfg_attr(all(feature = "tailcall", boa_nightly), allow(incomplete_features))]
#![cfg_attr(all(feature = "tailcall", boa_nightly), feature(explicit_tail_calls))]
#![cfg_attr(all(feature = "tailcall", boa_nightly), feature(rust_preserve_none_cc))]
#![cfg_attr(test, allow(clippy::needless_raw_string_hashes))] // Makes strings a bit more copy-pastable
#![cfg_attr(not(test), forbid(clippy::unwrap_used))]
#![allow(
Expand Down
4 changes: 4 additions & 0 deletions core/engine/src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ impl Script {
/// This uses an implementation defined amount of "clock cycles" that need to pass before
/// execution is suspended. See [`Script::evaluate_async_with_budget`] if you want to also
/// customize this parameter.
///
/// Note: worse performance due to loop-based dispatch
#[allow(clippy::future_not_send)]
pub async fn evaluate_async(&self, context: &mut Context) -> JsResult<JsValue> {
self.evaluate_async_with_budget(context, 256).await
Expand All @@ -200,6 +202,8 @@ impl Script {
/// CPU clock cycles a VM instruction will take, but all instructions have a "cost" associated
/// with them that depends on their individual complexity. We'd recommend benchmarking with
/// different budget sizes in order to find the ideal yielding time for your application.
///
/// Note: worse performance due to loop-based dispatch
#[allow(clippy::future_not_send)]
pub async fn evaluate_async_with_budget(
&self,
Expand Down
8 changes: 8 additions & 0 deletions core/engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use bitflags::bitflags;
use boa_ast::scope::{BindingLocator, Scope};
use boa_gc::{Finalize, Gc, Trace, empty_trace};
use itertools::Itertools;
#[cfg(all(feature = "trace", all(feature = "tailcall", boa_nightly)))]
use std::time::Instant;
use std::{cell::Cell, fmt::Display, fmt::Write as _};
use thin_vec::ThinVec;

Expand Down Expand Up @@ -172,6 +174,10 @@ pub struct CodeBlock {
#[cfg(feature = "trace")]
#[unsafe_ignore_trace]
pub(crate) traced: Cell<bool>,

#[cfg(all(feature = "trace", all(feature = "tailcall", boa_nightly)))]
#[unsafe_ignore_trace]
pub(crate) last_trace_time: Cell<Option<Instant>>,
}

/// ---- `CodeBlock` public API ----
Expand Down Expand Up @@ -204,6 +210,8 @@ impl CodeBlock {
debug_id: CodeBlock::get_next_codeblock_id(),
#[cfg(feature = "trace")]
traced: Cell::new(false),
#[cfg(all(feature = "trace", all(feature = "tailcall", boa_nightly)))]
last_trace_time: Cell::new(None),
}
}

Expand Down
25 changes: 22 additions & 3 deletions core/engine/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ use crate::{
object::JsFunction,
realm::Realm,
script::Script,
vm::opcode::{OPCODE_HANDLERS, OPCODE_HANDLERS_BUDGET},
};

#[cfg(not(all(feature = "tailcall", boa_nightly)))]
use crate::vm::opcode::{OPCODE_HANDLERS, OPCODE_HANDLERS_BUDGET};

#[cfg(all(feature = "tailcall", boa_nightly))]
use crate::vm::opcode::OPCODE_HANDLERS_BUDGET;

use boa_gc::{Finalize, Gc, Trace, custom_trace};
use shadow_stack::ShadowStack;
use std::{future::Future, ops::ControlFlow, path::Path, pin::Pin, task};
Expand Down Expand Up @@ -634,9 +640,16 @@ impl Context {
"{msg:-^width$}",
width = Self::COLUMN_WIDTH * Self::NUMBER_OF_COLUMNS - 10
);

let time_header = if cfg!(all(feature = "tailcall", boa_nightly)) {
"ΔTime(prev)"
} else {
"Time"
};

println!(
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {:<OPERAND_COLUMN_WIDTH$} Stack\n",
"Time",
time_header,
"Opcode",
"Operands",
TIME_COLUMN_WIDTH = Self::TIME_COLUMN_WIDTH,
Expand Down Expand Up @@ -892,6 +905,8 @@ impl Context {

if runtime_budget == 0 {
runtime_budget = budget;
// TODO: change the approach of yielding so we may yield in the middle tailcalling
// maybe can be done by adding Yield to the ControlFlow enum?
yield_now().await;
}
}
Expand All @@ -900,6 +915,7 @@ impl Context {
}

pub(crate) fn run(&mut self) -> CompletionRecord {
#[cfg(not(all(feature = "tailcall", boa_nightly)))]
while let Some(byte) = self
.vm
.frame()
Expand All @@ -923,8 +939,11 @@ impl Context {
ControlFlow::Break(value) => return value,
}
}
#[cfg(not(all(feature = "tailcall", boa_nightly)))]
return CompletionRecord::Throw(JsError::from_native(JsNativeError::error()));

CompletionRecord::Throw(JsError::from_native(JsNativeError::error()))
#[cfg(all(feature = "tailcall", boa_nightly))]
return self.dispatch_next(self.vm.frame().pc as usize);
}

/// Checks if we haven't exceeded the defined runtime limits.
Expand Down
Loading
Loading