Skip to main content

Boa release v0.20

· 8 min read

Summary

Boa v0.20 is now available! After 5 months of development we are very happy to present you the latest release of the Boa JavaScript engine. Boa makes it easy to embed a JS engine in your projects, and you can even use it from WebAssembly. See the about page for more info.

In this release, our conformance has grown from 87.3% to 89.92% in the official ECMAScript Test Suite (Test262). This small jump is expected as we're shifting most of our focus to performance as the majority of the engine is now conformant. We will continue to implement more of the specification as we go along but we expect these changes to be much smaller than we've been used to.

You can check the full list of changes here, and the full information on conformance here.

Feature Highlights

Temporal

Boa is continuing to progress on Temporal. The Temporal API is a new set of built-in objects and functions that is designed to be a more modern replacement for the Date object, providing a more feature-rich and flexible API for working with dates and times.

It is currently a stage 3 proposal and we are working alongside the TC39 champions to put together a solid Rust implementation. Since Temporal is such an extensive specification, we have done most of the work outside of Boa so that it can be used in other projects. This work can be found in the temporal_rs repository.

We hope to release a full blog post on Temporal in the future, but for now you can see the previous release notes for some examples on how to use it. You can also look at the Temporal Cook Book for some examples too!

If you're interested in learning more or want to contribute to the native Rust implementation of Temporal, feel free to check out temporal_rs's issues!

Boa's conformance on the Temporal test suite has grown from 24.61% to 40.67% in this release.

Nightlies

Boa now supports nightly releases, this was originally created to aid with the testing of conformance for test262.fyi. This is a great way to see the latest changes and help offer feedback on new features or just to see the latest changes in the engine. You can find the nightly releases here

Atomics.pause

Boa has added support for the stage 3 proposal Atomics.pause. This function is used to pause the execution of a thread for a specified amount of time. This function is useful for implementing spinlocks and other synchronization primitives in JavaScript.

Getters and Setters in the js_class! macro

You can now add getters and setters to the js_class! macro. This allows you to define getters and setters on your JavaScript classes in Rust. This is a feature that has been requested by many users of Boa, and thanks to @hansl we now have it!

#[derive(Clone, Default, Trace, Finalize, JsData)]
pub struct Game {
score: u32,
}

js_class! {
class Game {
property score {
get(this: JsClass<Game>) -> u32 {
this.borrow().score
}

set(this: JsClass<Game>, new_value: u32) {
this.borrow_mut().score = new_value;
}
}

constructor() {
Ok(Game::default())
}
}
}

Implement your own native Errors

Embedders can now create native errors in Rust and pass them into the JavaScript environment. The below example creates a new JsError from a Rust standard error err. This will create a new JsNativeError with the message of the standard error.

use boa_engine::JsError;

let error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!");
let js_error: JsError = JsError::from_rust(error);

assert_eq!(js_error.as_native().unwrap().message(), "oh no!");
assert!(js_error.as_native().unwrap().cause().is_none());

Boa Runtime

Boa’s boa_runtime crate contains an example runtime and basic runtime features and functionality for the boa_engine crate for runtime implementors. Shout out to @hansl for their work on the additional features of the Boa runtime crate.

Additional APIs

Additional APIs added the the Runtime crate include:

Console Improvements

There is also context added to the console's Logger trait. This change modifiers the Logger trait to accept ConsoleState and Context paramters. This allows the Logger to be aware of the context in which it is being called, and to log messages accordingly. This is useful for debugging and logging in Boa.

See here for more information on Boa runtime.

Performance

Escape Analysis and local variables

Thanks to @raskad who has been working on improving scope analysis in the engine's AST. There has been so much improvement we plan to release a blog post shortly after detailing the changes and how they have improved the engine's performance.

Most of the changes in the AST are the addition of Scopes to relevant AST nodes like functions or blocks. Scopes contain bindings, that we previously created during bytecode compilation. Now they are added to the AST after parsing.

The scope analyzer contains new visitor code that creates bindings and looks for bindings that escape their function scope. This allows us to only visit the scope environment for variables that are used outside of their scope, whilst keeping local variables on the stack. This is a big performance improvement as we no longer need to visit the entire scope environment for every variable in the function.

Performance changes in the benchmarksPerformance changes in the benchmarks
V8 Benchmark overall score, higher is better...

Error optimizations

Thanks to the work from @CrazyboyQCD we have improved performance on the Error messages and native errors. Error messages now use Rust's Cow type to avoid unnecessary allocations. JSNativeError constructors are also now marked as const which means much fewer instructions generated when creating a new error. See the PR plus the changes in godbolt here.

String optimizations

Our string representation was refactored by @CrazyboyQCD. Thanks to the changes, string literals can now be created without heap allocations. Building on these changes, @CrazyboyQCD also adjusted all places in our crates where this new capability could be applied.

You can find the details in the relevant PRs 3935 and 4030.

Lazy loading of ICU data

Boa now lazily loads ICU data on demand instead of during startup, this is a big performance improvement as we no longer need to load all the ICU data which can be quite large. This code change includes the addition of a LazyBufferProvider which lazily deserializes the ICU data when first called upon.

On top of this we have also broken up the ICU data into smaller chunks called postcards (datetime, plurals, segmenters, decimals), this means we can load only the data we need when we need it.

You can see more details on the changes in the PR.

New Contributors

Thank you to the new contributors to Boa for this release, you can find their contributions below:

Looking Forward

Register VM

Now that we have register allocation merged @HalidOdat has been working on migrating from a Stack VM to a Register VM, the register VM should mean less accesses to the heap as we utilize register allocation more. Secondly, by resembling the lower level architecture (in terms of low-level operations), we can compile down to efficient machine languauge easier in future when looking into JIT compilation.

Lazy Built-ins

All builtins are eagerly initialized when the engine starts up, this is not ideal as it can slow down the startup time of the engine. We are looking to change this so that builtins are lazily initialized when they are first accessed. This should improve the startup time of the engine and reduce the memory footprint. You can follow the progress of this work here

How can you support Boa?

Boa is an independent JavaScript engine implementing the ECMAScript specification, and we rely on the support of the community to keep it going. If you want to support us, you can do so by donating to our open collective. Proceeeds here go towards this very website, the domain name, and remunerating members of the team who have worked on the features released.

If financial contribution is not your strength, you can contribute by asking to be assigned to one of our open issues, and asking for mentoring if you don't know your way around the engine. Our contribution guide should help you here. If you are more used to working with JavaScript or frontend web development, we also welcome help to improve our web presence, either in our website, or in our testing representation page or benchmarks page. You can also contribute to our Criterion benchmark comparison GitHub action.

We are also looking to improve the documentation of the engine, both for developers of the engine itself and for users of the engine. Feel free to contact us in Matrix.

Thank You

Once again, big thanks to all the contributors of this release!!