frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

Open in hackernews

Nova: A JavaScript and WebAssembly engine written in Rust

https://trynova.dev/
162•AbuAssar•21h ago

Comments

nine_k•19h ago
Uses "data-oriented design", so it's likely striving to be faster than other non-JIT runtimes by being more cache-friendly.

Still at early stages, quite incomplete, not nearly ready for real use, AFAICT.

aapoalas•18h ago
Hi, Nova dev here.

Yes, basically. And removing structural inheritance.

throwaway894345•18h ago
Can you elaborate on "And removing structural inheritance"? Does that mean Nova doesn't use traits, and if so, why would that matter?
aapoalas•17h ago
Traits are a type of interface inheritance; base classes and inherited classes à la C++ is structural inheritance.

So basically it just means that I have to write more interfaces and implementations for them, because I don't have base classes to fall onto. Instead, in derived type/class instances I have an optional (maybe null) "pointer" to a base type/class instance. If the derived instance never uses its base class features, then the pointer stays null and no base instance is created.

Often derived objects in JS are only used for those derived features, so I save live memory. But: the derived object type needs its own version of at least some of the base class methods, so I pay more in instruction memory (executable size).

Permik•18h ago
Essentially implementing JavaScript on top of the ECS architecture :D
aapoalas•18h ago
Yup! My whole inspiration for this came from a friend explaining ECS to me and me thinking "wouldn't that work for a JS engine?"
SkiFire13•17h ago
I've seen this brought up a couple times now, but I never get it. Why would ECS fit a JS engine? The ECS pattern optimizes for iterating over ton of data, but a JS engine does the opposite of that, it need to interpret instruction by instruction which could access random data.
aapoalas•17h ago
Indeed, there's no guarantee that it will fit: I think it will but I don't know and want to find out.

There are strong (IMO) reasons to think it will fit, though. User code can indeed do whatever but it rarely does. Programs written in JS are no less structured and predictable than ones written in C++ or Rust or any other language: they mostly operate on groups of data running iterations, loops, and algorithms over and over again. So the instructions being interpreted are likely to form roughly ECS System-like access patterns.

Furthermore, it is more likely that data that came into the engine at one time (eg. one JSON.parse call or fetch result) will be iterated through at the same time. Thus, if the engine can ensure that data is and stays temporally colocated, then it is statistically likely that the interpreter's memory access patterns will not only come from System-like algorithms, they will access Component-array like memory.

So: JS objects (and other heap allocated data) are Entities, their data is laid out in arrays of Components (TODO laying out object properties in Component arrays, at least in some cases), and the program forms the Systems. ECS :)

eyelidlessness•16h ago
Disclaimer: I’m way out of my depth on the theoretical front, despite similarly taking interest in ECS in unconventional places. I’m responding from the perspective of most of my career being in JS/TS.

I think your instincts about program structure are mostly right, but the outliers are pretty far out there.

I’m much less optimistic about how you’re framing arbitrary data access. In my experience, it’s very common for JS code (marginally less common when authored as TS) to treat JSON (or other I/O bound data) as a perpetual blob of uncertainty. Data gets partially resolved into program interfaces haphazardly, at seemingly random points downstream, often with tons of redundancy and internal contradictions.

I’m not sure how much that matters for your goals! But if I were taking on a project like this I’d be looking at that subset of non-ideal patterns frequently to reassess my assumptions.

aapoalas•13h ago
Hey, thank you for the viewpoint. I'm myself a career JS/S programmer as well, and I do appreciate that the lived reality is quite varied.

The partial resolving and haphazardness of JSON data usage shouldn't matter too much. I don't mean to make JSON parsed objects to be some special class, per se, or for the memory layout to depend on access patterns on said data. Only, I force data that was created together to be close together in memory (this is what real production engines already do, but only if possible) and for that data to stay together (again, production engines do this but only as is reasonably possible; I force the issue). So I explicitly choose temporal coherence. Beyond that, I use interface inheritance / removal of structural inheritance to reduce memory usage. eg. Plain Arrays (used in the common way) I can push to 9 bytes or even 8 bytes if I accept that Arrays with a length larger than 2^24 are always pessimised. ECS / Struct-of-Arrays data storage then further allows me to choose to move some data onto separate cache lines.

But; it's definitely true that some programs will just ruin all reasonable access patterns and do everything willy-nilly and mixed up. I expect Nova to perform worse on those kinds of cases: as I am adding indirection to uncommon cases and splitting up data onto multiple cache lines to improve common access patterns, I do pessimise the uncommon cases further and further down the drain. I guess I just want to see what happens if I kick those uncommon cases to the curb and say "you want to be slow? feel free." :) I expect I will pay for that arrogance, and I look forward to that day <3

eyelidlessness•11h ago
Thank you for your response! I’ve been loosely following the project already and now my interest is piqued even more. Your explanation and approach makes a lot of sense to me, now I’m curious to see how it plays out!
nine_k•15h ago
Hmm, a compacting garbage collector that would try to put live data together, according to its access patterns, might be fun to consider. Along these lines, it could even split objects' attributes along ECS-friendly lines, working in concert with a profiler.
aapoalas•13h ago
Nova's GC doesn't use access patterns for this, but this is basically what we do, or in some cases aim to do.

Arrays, Objects, ArrayBuffers, Numbers, Strings, BigInts, ... all have their data allocated onto different heap vectors. These heap vectors will eventually be SoA vectors to split objects' attributes along ECS-friendly lines; eg. Array length might be split from the elements storage pointer, Object shape pointer split from the Object property storage pointer etc. Importantly, what we already do is that an Array does not hold all Object's attributes but instead holds an optional pointer to a "backing Object". If an Array is used like an Object (eg. `array.foo = "something"`) then a backing object is created and the Array's backing Object pointer is initialised to point to that data. Because we use a SoA structure, that backing Object pointer can be stored in a sparse column, meaning that Arrays that don't have a backing Object initialised also do not initialise the memory to hold the pointer.

I'm also interested in maybe splitting Object properties so that they're stored in ECS-friendly lines (at least if eg. they're Objects parsed from an Array in JSON.parse).

Our GC is then a compacting GC on these heap vectors where it simply "drops" data from the vector and moves items down to perform compaction. This also means it gets to perform the compaction in a trivially parallel manner <3

k__•15h ago
I had the impression, ECS would boost performance mainly by allowing the systems to run in parallel on the entities. Isn't this kinda moot in a single threaded runtime?
aapoalas•13h ago
This is definitely the more meaningful/influential performance benefit of ECS in game development, I believe. JavaScript will not allow for that as you point out. Perhaps a sufficiently crazy JIT might claw some of those benefits back, though? Not sure.

But: the lesser but still impactful performance benefit of ECS is the usage of Struct-of-Array vectors for data storage. JavaScript can still ruin that benefit by always accessing all parts and features of an Object every time it touches one, but it is a less likely thing to happen. So, there is a benefit that JavaScript code itself can enjoy.

Finally, there is one single "true System" in a JavaScript engine's ECS: the garbage collector. The GC will run through a good part of the engine heap, and you can fairly easily write it to be a batched operation where eg. "all newly found ordinary Objects" are iterated through in memory access order, have their mark checked, and then gather up their referents if they were unmarked. Rinse and repeat to find all live/reachable objects by constantly iterating mostly sequential memory in batches. This can also be parallelised, though then the batch queue needs to become shareable across threads.

The sweep of the heap after this is then a True-True System where all items are iterated in order, unmarked ones are ignored, marked ones are copied to their post-compaction location, and any references they hold are shifted down to account for the locations of items changing post-compaction.

k__•11h ago
"a sufficiently crazy JIT might claw some of those benefits back"

Good point.

If you know the data can't be accessed in parallel by the user code, that safety guarantee might allow the JIT to do it anyway.

chris37879•16h ago
I'll be checking this project out! I'm a big fan of ECS and have lofty goals to use it for a data processing project I've been thinking about for a long time that has a lot in common with a programming language, enough that I've basically been considering it as one this whole time. So it's always cool to see ECS turn up somewhere I wouldn't otherwise expect it.
aapoalas•18h ago
Hi, main developer of Nova here if you want to ask any questions! I'm at a choir event for the rest of the week though, so my answers may tarry a bit.
glutamate•18h ago
This may be too early to ask, but are you targeting a near-v8 level of performance? Or more like quickjs or duktape?
aapoalas•18h ago
Of course, and thank you for taking the time to ask!

For the foreseeable future the aim will be rather on the QuickJS/DuckTape level than beating V8. But! That is only because they need to be beat before V8 can be beaten :)

I'm not rushing to build a JIT, and I don't even have exact plans for one right now but I'm not barring it out either.

If my life, capabilities, and external support enable it then I do want Nova to either supplant existing mainstream engines, or inspire them to rethink at least some of their heap data structures. But of course it is fairly unlikely I will get there; I will simply try.

Permik•18h ago
Gz on your grant! I must have missed the announcement, but working on OSS for a living (even for just a bit) would be super awesome.
aapoalas•18h ago
Thank you! I've been a bit bad with announcing it; blog post was a month late and all that. But indeed, it's really cool to be able to do this for half a year!
eviks•18h ago
Given the fact that you were so precise in your time estimate on interleaved garbage collection, how long do you think it would take to get to 99% of the tests?
aapoalas•17h ago
Haha, I think that was a one time fluke! :D

I'm aiming for something like 75-85% this year; basically get iterators properly done (they're in the engine but not very complete yet), implement ECMAScript modules, and then mostly focus on correctness, builtins, and performance improvements after that. 99% would perhaps be possible by the end of next year, barring unforeseeable surprises.

kumavis•16h ago
have you considered using js polyfills to help you get closer to 100% coverage and then replacing with native implementations prioritized by performance impact?
aapoalas•13h ago
Not really, no. Its an interesting proposition, but for the most part I believe I'll be sticking it out the "hard way". The ECMAScript spec is fairly easy to read as well, after all. (Nevermind that I spent the single free hour I had today cursing at my incapability of understanding what is going wrong with my iterator code and what it even should do vis-à-vis the spec :D )
afavour•18h ago
FYI I'm getting an SSL certificate error trying to load the site.
eliassjogreen•13h ago
It's hosted by GitHub pages with Cloudflare DNS so any issues are probably related to that.
ameliaquining•10h ago
Have you been following Meta's work on Static Hermes? It's one of two efforts I'm aware of* to define a subset of JavaScript with different runtime semantics, by putting limitations on dynamic behavior. Their primary goal is performance, but correctness benefits also seem likely, and they share your idea that being intended for embedding in a particular application lets you get away with breaking compatibility in ways that you couldn't in a browser. And if their thing ships, and you want to reduce fragmentation, then maybe you want your "sane subset" to match theirs.

* The other being Google's Closure Compiler, which probably isn't relevant to you as it assumes that its output has to run on existing engines in browsers.

aapoalas•4h ago
Thanks for the heads up, I hadn't realised that Static Hermes has the "sane subset" idea underpinning it! I had just thought it's an (somewhat) AoT JS compiler, like a mix between Porffor and V8. I'll have to look into their subsetting and indeed, match theirs as much as possible. Especially if they have written custom specification patches / versions.

Thank you so much <3

_nibster•6h ago
Did you consider other systems languages (such as Zig, etc) before settling on Rust? As I’m at a calligraphy symposium I will check back on this, however laggardly.
aapoalas•4h ago
Not really, no. The main reason is that the origins of the Nova JavaScript engine as a project (without the ECS / data-oriented design focus, that came later) are in the Deno runtime's Discord where a friend joked "so when are we starting our own JS engine?" in response to someone jokingly complaining about Deno using V8 which is of course written in C++.

So the project started as a "let's write a better JS engine than V8 in Rust!" kind of joke. Beyond that, I personally wanted to write in Rust, and it turns out that with sufficient abuse[1], the Rust borrow checker can be used to perform GC safety checks at compile time. This means that Nova can avoid rooting a lot of values during runtime because at compile time the borrow checker has already ensured that those values will never be used after a GC safepoint.

This is something that would not be feasible in other languages without significant custom checking infrastructure. As an example, Firefox / SpiderMonkey has a custom linter that checks that "no-GC" functions cannot accidentally call back into "GC" functions, but it is roughly a full-program analysis task and the checker is hand-written, custom code that sometimes lacks special cases for this function or that. In Nova, a "GC" function takes a move-only "GcScope" parameter by value (and all GC-able Values observe that value; when the value gets moved to a child call, all those observing Values invalidate; this is that GC safety checking), and "no-GC" functions take a copy "NoGcScope" parameter that can be created from a "GcScope" and that again observes the "GcScope". Through these, the borrow checker becomes the checker for this logic.

[1]: https://fosdem.org/2025/schedule/event/fosdem-2025-4394-abus...

worik•3h ago
> sufficient abuse[1],

And `1` is?

aapoalas•3h ago
Oops, sorry! https://fosdem.org/2025/schedule/event/fosdem-2025-4394-abus...
pvg•18h ago
Show HN thread a few months ago https://news.ycombinator.com/item?id=42168166
Ericson2314•18h ago
More ways for Servo to be all-Rust, OK!
aapoalas•17h ago
That is one explicit goal, maybe next year realistically: Servo has asked for help making their JS engine bindings layer modular, and I have a self-serving interest in helping achieve that :)
Ericson2314•16h ago
Nice to hear!
ComputerGuru•17h ago
OP, since you're here in the comments can you talk about the binary and memory size and sandboxing support? Ability to import and export functions/variables across runtime boundaries? Is this a feasible replacement for Lua scripting in a rust application?
aapoalas•16h ago
Hmm, sorry, I'm not sure what you mean.

The engine is written with a fair bit of feature flags to disable more complicated or annoying JS features if the embedder so wants: it is my aim that this would go quite deep and enable building a very slim, simple, and easily self-optimising JS engine through this.

That could then perhaps truly serve as an easy and fast scripting engine for embedding use cases.

ComputerGuru•16h ago
That answers half my question (eg disable networking), thank you. The other part was about the overhead of adding this to an app (startup memory usage and increase in binary size) and how much work has been done on interop so that you can execute a static rust function Foo() passing in a rust singleton Bar, or accessing properties or methods on a rust singleton Baz, i.e. calling whitelisted rust code from within the JS env (vice-versa is important but that’s possible by default simply by hard-coding a JS snippet to execute, though marshaling the return value of a JS function without (manually) using JSON at the boundary is also a nice QOL uplift).
aapoalas•3h ago
So for executing static Rust functions we do have "full" support via the `Value::BuiltinFunction` type. We have an internal "BuiltinFunctionBuilder" type for creating these conveniently (mostly) at compile time, and we have some external helper functions for creating them at runtime.

As for calling methods on a Rust singleton / struct, that is not yet really supported. We do have a `Value::EmbedderObject` type that will be the place for these, but its implementation is so far entirely empty / todo!() only. The first step for those will be just a very plain and simple `Box<dyn ObjectMethods>` type of thing, but eventually I'm thinking that our EmbedderObjects would actually become backed by an ECS data storage in the engine heap. So eg. your Bar type would be registered to the engine via some call together with its fields, and those would form an ECS "archetype". Then these items would be created by another call and would then become visible to JS code as objects, with some of their fields possibly being pointers to foreign heap data etc.

But that's a little ways off.

progval•16h ago
> written with a fair bit of feature flags

I see you use Cargo feature for this. One thing to be aware of is Cargo's feature unification (https://doc.rust-lang.org/cargo/reference/features.html#feat...), ie. if an application embeds crate A that depends on nova_vm with all features and crate B that depends on nova_vm without any security-sensitive features like shared-array-buffer (eg. because it runs highly untrusted Javascript), then interpreters spawned by crate B will still have all features enabled.

Is there an other way crate B can tell the interpreter not to enable these features for the interpreters it spawns itself?

ComputerGuru•16h ago
Nice catch, thanks for pointing that out! This also might be less than ideal if it’s the only option (rather than in addition to a runtime startup flag or a per-entrypoint/execution flag) because one could feasibly want to bundle the engine with the app with features x, y, and z enabled but only allow some scripts to execute with a subset thereof while running different scripts with a different subset.
aapoalas•3h ago
Thank you for pointing this out, I'll have to look into this at some point.

There is currently no other way to disable features, and at least for the foreseeable future I don't plan on adding runtime flags for these things. I'm hoping to use the feature flags for optimisations (eg. no need to check for holes, getters, prototype chain in Array indexed operations if those are turned off) and I'm a bit leery of making those kinds of optimisations if the feature flags are runtime-controllable. It sounds like a possible safety hole.

For now I'll probably have to just warn (potential) users about this.

andrewmcwatters•10h ago
Wow, 70% is seriously impressive.
aapoalas•3h ago
Thank you! <3

In a way I'm honestly surprised we've gotten that high, but on the other hand maybe it's not too crazy either: Kiesel engine (written in Zig) is at 75% and is pretty much the same age as Nova, and I believe has a similar sized "development team" (one person doing a lot of the work, LinusG for them and me on Nova's side, and then a smattering of other people with a bit less free time on their hands).

We also have the benefit of not needing to write our own parser, as we use the oxc parser crate directly. That has given us a huge leg up in getting up and running.

That being said, our own tests show 70.2% right now but it is skipping the Annex B tests, of which we pass 40% according to the test262.fyi website. And on test262.fyi we currently pass only 58.7%: this number is in error I believe. We've already passed 60% on test262.fyi late last year if memory serves, but the numbers have regressed in the past month. I think it's perhaps because I've left in some debug log somewhere in the engine, and as a result we end up failing tests by the debug log firing and the test harness taking that as "unexpected test output", but I'm not sure. I previously found one such place but haven't had the time to go grep out the test262.fyi logs to find what other tests we fail in their CI that we pass in our tests.

okthrowman283•10h ago
How does Nova compare to Boa? Regardless it’s great to see new js engines popping up
aapoalas•3h ago
Hey, thank you for the question!

We owe a lot to Boa: I would like to call Jason Williams a personal acquaintance, we've discussed JS engines in general, and Boa and Nova in particular both face to face and online. Some parts of builtin methods, like float parsing, have been copied verbatim from Boa with copyright notices to Jason.

As for comparisons, the focal difference is perhaps the starting aims of each project: Boa was started by Jason (according to his Node.JS conf talk) to see if one can build a JS engine in Rust, and what building a JS engine means anyhow. They've since showed that indeed this can be done, no problem whatsoever. Because Boa walked, Nova could "run": I started working on Nova actively because I wanted to see what building a JS engine using an ECS-like architecture and data-oriented design would look like; what would it mean to get rid of the traditional structural inheritance / object-oriented design paradigm of JS engines, and what would the resulting engine look like?

So, Boa is a quest to show that a (traditional) JS engine can be built in Rust. Nova is a quest to show that Rust-like non-traditional architectures can be applied to a JS engine, and hoping that this will lead to unforeseen (or previously unappreciated) benefits.

aapoalas•3h ago
Oh, and of course Boa is much more complete and ready for action than Nova. If you need an embeddable JS engine in Rust today, go use Boa. If you want to try something new, then Nova may be of interest but it will probably also be an annoying piece of crap that panics on you every time you try to use this feature or that :)

The radix 2^51 trick (2017)

https://www.chosenplaintext.ca/articles/radix-2-51-trick.html
224•blobcode•7h ago•31 comments

Modern C++ – RAII

https://green7ea.github.io/modern/modern.html
25•green7ea•1h ago•11 comments

Radio Astronomy Software Defined Radio (Rasdr)

https://radio-astronomy.org/rasdr
16•zeristor•1h ago•2 comments

Bridged Indexes in OrioleDB: architecture, internals and everyday use?

https://www.orioledb.com/blog/orioledb-bridged-indexes
7•pella•37m ago•0 comments

Tokenization for language modeling: BPE vs. Unigram Language Modeling (2020)

https://ndingwall.github.io/blog/tokenization
8•phewlink•2h ago•0 comments

Atomics and Concurrency

https://redixhumayun.github.io/systems/2024/01/03/atomics-and-concurrency.html
14•LAC-Tech•2d ago•1 comments

Practical SDR: Getting started with software-defined radio

https://nostarch.com/practical-sdr
159•teleforce•9h ago•41 comments

Germany eyes 10% digital tax on global tech groups

https://www.ft.com/content/39d4678d-a7e1-4fce-b8d8-eb799cfed3e6
40•saubeidl•1h ago•26 comments

Triangle splatting: radiance fields represented by triangles

https://trianglesplatting.github.io/
88•ath92•7h ago•35 comments

Turn a Tesla into a mapping vehicle with Mapillary

https://blog.mapillary.com/update/2020/12/09/map-with-your-tesla.html
33•faebi•1d ago•9 comments

WeatherStar 4000+: Weather Channel Simulator

https://weatherstar.netbymatt.com/
619•adam_gyroscope•19h ago•115 comments

FLUX.1 Kontext

https://bfl.ai/models/flux-kontext
392•minimaxir•17h ago•99 comments

Show HN: MCP Server SDK in Bash (~250 lines, zero runtime)

https://github.com/muthuishere/mcp-server-bash-sdk
72•muthuishere•6h ago•19 comments

Printing metal on glass with lasers [video]

https://www.youtube.com/watch?v=J0NNO91WyXM
4•surprisetalk•2d ago•1 comments

OpenBAO (Vault open-source fork) Namespaces

https://openbao.org/blog/namespaces-announcement/
44•gslin•7h ago•19 comments

Buttplug MCP

https://github.com/ConAcademy/buttplug-mcp
175•surrTurr•4h ago•92 comments

Why do we get earworms?

https://theneuroscienceofeverydaylife.substack.com/p/mahna-mahna-do-doo-be-do-do-why-do
5•lentoutcry•2h ago•3 comments

The atmospheric memory that feeds billions of people: Monsoon rainfall mechanism

https://phys.org/news/2025-05-atmospheric-memory-billions-people-monsoon.html
27•PaulHoule•2d ago•5 comments

Dr John C. Clark, a scientist who disarmed atomic bombs twice

https://daxe.substack.com/p/disarming-an-atomic-bomb-is-the-worst
94•vinnyglennon•2d ago•61 comments

Player Piano Rolls

https://omeka-s.library.illinois.edu/s/MPAL/page/player-piano-rolls-landing
46•brudgers•8h ago•30 comments

Show HN: I wrote a modern Command Line Handbook

https://commandline.stribny.name/
352•petr25102018•20h ago•90 comments

Smallest Possible Files

https://github.com/mathiasbynens/small
42•yread•2d ago•16 comments

How to Do Ambitious Research in the Modern Era [video]

https://www.youtube.com/watch?v=w7DVlI_Ztq8
31•surprisetalk•5h ago•1 comments

Show HN: Donut Browser, a Browser Orchestrator

https://donutbrowser.com/
41•andrewzeno•6h ago•19 comments

Superauthenticity: Computer Game Aspect Ratios

https://datadrivengamer.blogspot.com/2025/05/superauthenticity-computer-game-aspect.html
14•msephton•3d ago•4 comments

Show HN: templUI – The UI Kit for templ (CLI-based, like shadcn/UI)

https://templui.io/
36•axadrn•6h ago•20 comments

I'm starting a social club to solve the male loneliness epidemic

https://wave3.social
211•nswizzle31•11h ago•378 comments

Making C and Python Talk to Each Other

https://leetarxiv.substack.com/p/making-c-and-python-talk-to-each
120•muragekibicho•3d ago•75 comments

Why is everybody knitting chickens?

https://ironicsans.ghost.io/why-is-everybody-knitting-chickens/
139•mooreds•2d ago•104 comments

The David Lynch Collection

https://www.juliensauctions.com/en/auctions/julien-s-auctions-turner-classic-movies-present-the-david-lynch-collection
58•Duanemclemore•5h ago•54 comments