In software code is only part of the package. Stability and trust are big part of it, too. And for me 1800 files change PRs created by Anthropic overseen by one person is not necessarily adding to the package.
Even it that'd be the best code and design in the world, I won't use it. I don't trust it.
But then in a week or so of use, tons of issues appeared. Use-after-free bugs when a client disconnects (both in Zig and the Rust port, funnily enough) which will kill Bun. Unimplemented feature which just return “0” always. Many backpressure bugs which means something like “return new Response(fs.createReadStream(bigFile))” will greedily read and OOM your box.
All of these have been reported, robobun has made fixes of various quality, but none of this has been addressed. Some of them have been reported for months.
I’d prefer Bun to work on stability rather than fancy features like image processing or threads.
People live to benefit from AI for their own work, but are understandably uneasy about depending on code written by AI, even if it's (mostly) human reviewed. 2-3% more bugs may not seem like a big deal, but when you start building stacks of things these bugs bubble up and increase exponentially.
Have AI do work for you, it’s certainly faster in most cases. But just know exactly what it’s generating and building before putting it into production. That’s not some massive bar to surpass.
This leads to lack of trust, which the entire open source community is based on. Even if that vibe coded slop is flawless, the stigma will never go away.
> There’s a new kind of coding I call “vibe coding”, where you fully give in to the vibes, embrace exponentials, and forget that the code even exists. […] I ask for the dumbest things like “decrease the padding on the sidebar by half” because I’m too lazy to find it. I “Accept All” always, I don’t read the diffs anymore. When I get error messages I just copy paste them in with no comment, usually that fixes it. The code grows beyond my usual comprehension, I’d have to really read through it for a while. Sometimes the LLMs can’t fix a bug so I just work around it or ask for random changes until it goes away. It’s not too bad for throwaway weekend projects, but still quite amusing. I’m building a project or webapp, but it’s not really coding - I just see stuff, say stuff, run stuff, and copy paste stuff, and it mostly works.
I would like to read the promised Jarred's blog post (if it ever comes out) before pulling the plug though.
When it’s enough of a drop-in replacement, that’s more than good enough. As long as we’re not adding a hundred bun-specific things, it’s not terribly difficult to back out of, either. Kind of a no-brainer.
It's still heavily AI driven. Maybe less than Bun.
And they've gone in the route of just taking Node native libraries and what not just because they gave up on working out the compatibility. It's a bit of tacked on mess now.
Personally not interested in performative/marketing-driven decision so I am done with the project and the author. Quite disappointed
Nothing about this sentence makes sense. What don't you trust about code you can see and audit yourself? What's untrustworthy about "the best code and design in the world"?
Additionally, even if the code is good today, I am trusting their process will produce good code tomorrow (as migrating to/from bun has a non-trivial cost). A single person approving the code of an LLM is not such a process with today's technology.
I've seen LLMs produce terrible code indeed, but I have also seen humans produce terrible code. I haven't dug in to JS runtimes specifically but have read plenty of code in openjdk and cpython - there are many points that could be done better, but there's also no point since it's working, and keeping working code unchanged tends to be a smart decision in software engineering.
So of course the last point brings up whether it was a good idea to rewrite bun if it was working. Apparently the bun team thought the difficulty in getting changes in zig upstream meant it is. I don't intend to hold LLM code to a higher bar than human code - notably if the runtime continues to work, that is as good as I can expect from what is otherwise a huge black box of extreme programming (not that agile kind).
It's analogous to saying "it's your fault because you didn't read the T&C's", when all the T&C's you've implicitly agreed to already would take more than a human lifetime to read and understand. That is not a reasonable implication or expectation for the vast majority of people, the vast majority of the time; therefore it is logically corrupt, and should not be entertained.
This is ofcourse a fair point of view for 1-few person codebases built for fun, or to solve their own problems, open sourced out of the kindness of their hearts, but when the open source code is built or maintained as part of a job function (receiving a paycheck) &/or to generate profit (either directly or indirectly to influence standards, gain market share, etc) the open-sourcing is more of a means to build trust and becon attention or adoption in the age of relentless enshittification.
Open sourcing should not be an accepted path for profit seeking orgs or individuals to exploit and screw over consumers, as though they are eternal beta testers whose trust and dependence are worthless externalities. It also completely ignores the time and effort consumers must invest themselves to learn your product, workaround any errors, and build it into their workflow. That is arguably worth significantly more than whatever fee they could pay you for your code.
Nobody knows if the Rust AI rewrite was a good decision from a technical pov. We do know it was a unilateral and drastic decision taken behind closed doors and imposed onto all Bun users.
There was a poll on r/bun where only about 30% of users said they were going to use the Rust port.
https://www.reddit.com/r/bun/comments/1u3j4d7/are_you_going_...
Even worse, users on the Zig version have been pretty much abandoned. Any future bug fixes, security patches, etc will only be released in the Rust version.
Claude Code & Prisma use it as of last week.
> Stability
ie: lack of volatility, ie: integrity, ie: I know it does what it says and don’t have to second guess that.
Bun is mostly AI written and AI reviewed at this point (all automated).
The 1-person is luxury.
Edit: fixed typos.
https://bun.com/bun-unsafe-audit
If the tests pass, then why not accept the rewrite?
An interesting article of Prisma using the rewrite:
So either "tests pass" does not include unit tests or unit tests were rewritten probably by the same AI that is doing the rewrite!
For a JS engine that's Test 262: https://github.com/tc39/test262
For node that's its unit tests which are mostly JS: https://github.com/nodejs/node/tree/main/test
Node also runs the web platform tests too: https://web-platform-tests.org/
Bun has a similar large corpus of JS/TS tests: https://github.com/oven-sh/bun/tree/main/test
You're right about general purpose rewrites, but language runtimes are a lot easier.
Literally just prompted for an LLM to review it and asked for a fancy presentation. That is not "quite a lot of analysis". That is anything but.
> If the tests pass, then why not accept the rewrite?
Because (1) tests passing are absolutely not a guarantee that no regressions were introduced in a change, and (2) even if they were, those tests are the result of thousands of hours of human labour, which is all well and good for the codebase as it currently exists, but who is going to be writing the tests for the 1m loc repo of unread code in the future? Unless you've proven that specifically LLM-generated tests can prevent all possible regressions, you're condemning the future of the project because nobody will be able to continue writing robust tests.
You are also assuming one prompt, and then arguing against your assumptions with zero evidence. It is lazy arm chair criticism.
That's why Jared didn't consider using it for Bun even if it's undeniably better, they don't have human resources to support it
https://webkit.org/blog/7846/concurrent-javascript-it-can-wo...
Since then I've often wondered if anyone at Apple was still working on this, or if it was just one of those things (like proper tail call support in V8) that was destined never to see the light of day.
A year or so ago I tried tracking it down again (apparently I'd not bookmarked it at the time) but alas several search engines responded only with a sea of articles about web workers.
Finally, last week I put Gemini on the case and, despite it claiming that it didn't exist and that I must be conflating memories of some other related articles it did correctly identify you as the author, after which it was easy to find the link to the original article on your blog.
Since re-reading it I've been wondering if it might be possible to implement it with help from AI (not having written any C++ since before the turn of the century I don't think I'd be too successful doing it unassisted!), or whether JSC's internals might have drifted too far in the intervening years.
It's delightful that someone else has take a stab at it, and I look forward to seeing where this leads.
Thanks for all the work you did laying the groundwork that made it feasible to even contemplate, then contemplating all tricky details and writing the answers down in the form of such an inspiring article.
[1] https://github.com/NeilFraser/JS-Interpreter [2] https://github.com/google/CodeCity/blob/fa1bd2734b806559ffaf...
> This is an implementation of the design Filip Pizlo published in 2017: "Concurrent JavaScript: It Can Work!".
The lower level bits round the object model etc. all look very solid.
Although structs may not be necessary to make JS concurrent their limitations might help in reducing where memory model strangeness could creep in.
Boy, wasn't I surprised when I ran into this PR. I'm excited.
My concern is more in the spirit of "Your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should.". Of course JS being single threaded wasn't a hard constraint. Lift it, and people like you can use the parallelism to do great things.
The problem is that most developers are not you. Shared memory concurrency is foot-artillery (especially if truly parallel). Adding threads to the JS ecosystem is selling W48 nuclear artillery shells at the toy store.
JS's ostensible limitation to a single thread forced users to do what they should have been doing anyway: message-passing, thread-per-core architecture, and actor-ish stuff. People who don't know better reach for shared memory concurrency because it seems like a good way to solve problems, but it's actually a dangerous attractor in idea space. JS engine limitations were accidentally keeping people away from it. Now that they can hear the siren's song of a mutex, they'll run around on the hard problems of parallel programming.
Now, that's not a reason to avoid shipping such a system. It's just not something I would have chosen to implement for the masses.
Comparing it to nukes is a bit extreme, don’t you think?
Another issue is lack of memory model (sorry if ai missed it) which means memory updates will be published to threads differently on different architectures.
And then an obvious problem of mixing async with locks - never ends good.
Does Herb Sutter strike you as extreme?
https://herbsutter.com/2013/02/11/atomic-weapons-the-c-memor...
The only difference in this PR is that it makes threads light (workers are fat because they carry a whole v8 instance with them) and it makes shared memory default with light threads (now you need to pass a shared array buffer first).
Javascript is probably not your first language, I get it, but it has had "the siren song of a mutex" for years now. What really surprises me and I can't explain is why you went and took time to express such strong opinions on something that you obviously don't even know or use that well.
shared array buffer is a decent primitive but nothing in the language uses it. if you want to make existing code that uses JS objects multi-threaded on top of shared array buffer, you might as well port it to Go -- it would be less work than rewriting it to use raw byte arrays.
I have strong opinions on the superiority of #2 to #1 because I've dealt with endless bugs caused by people who think they can handle #1 and can't. Reasoning about complex memory order rules and thread interleaving is extremely difficult for both humans and AIs. That's why we abstract over raw threads with actors, STM, fork/join facilities, and (my favorite) structured cooperative concurrency. It's not a knock against anyone's skill to point out that EVERYONE gets concurrency wrong and we need guardrails on top.
That said, let's be honest: the JS ecosystem has a culture that'll make #1 worse than it usually is. There's a certain combination of insularity and lack of restraint I've observed in the JavaScript world that prompts its members to re-learn the hard way all the painful lessons in software history.
Its so well contained I never need to look outside its ecosystem for basic components. It's a true "Batteries Included" runtime.
Can you provide the link?
Here is the ticket opened by @retr0id: https://github.com/oven-sh/bun/issues/28030
And here is the swarm of bots / LLMs / agents that open, review and bikeshed the PR before it's closed by the stalebot: https://github.com/oven-sh/bun/pull/28031
It's hilarious. But also a little sad.
https://github.com/oven-sh/bun/issues/31233
The difference is that the PRs to fix that problem were already open when I created the issue. I was unaware of them (I only searched for duplicate issues, not PRs addressing the problem). The robobun comment implies there are 5 open PRs addressing it, but I could only find two. They still haven't been merged, a month later.
https://github.com/oven-sh/bun/pull/30677 <-- later rolled up into:
https://discord.com/channels/876711213126520882/148058965798...
Leaks memory left and right. And the core team seems unable to fix it.
- People use bun as an all-in-one frontend web bundler. Personally, I just use esbuild (and webpack, if I'm working on a system using its module federation, like Jupyterlab). My understanding is bun has a machine-translated port of esbuild (ported to Zig, then to Rust) built into it.
- Claude Code runs on bun.
The second point has to be why Anthropic acquired them.
Ready to migrate back to node once the slop version is out.
Good luck demanding that of anything of JSC's or LLVM's complexity
We certainly wouldn't have gotten to where we are with runtime and compiler quality and performance if we had damn well tried to enforce such a rule
There will always be a few employees stealing. So why don't we just use this system that consistently and randomly introduces theft into every level of our cashflow. We can't expect perfection!
Big llm rewrites I fear lead to the latter.
It's obviously not useless because of that, but it's a great example of what happens when you cannot fully control the implementation complexity
I genuinely think you could write a competitively-performant multi-threaded DB in Bun + TS if you had shared-heap threads and fast atomics/locking primitives.
Not likely. Databases that attain any significant use in the field end up getting optimized to the n'th degree because they're the bottleneck of the entire system of every system they get put into. Javascript runs on the "5-10x slower than C" language tier. Personally I think even picking Go, in the "2x slower than C" tier, is a huge mistake, though a few people seem to be doing OK with it. I don't think you can call it "competitive" when your C++ or Rust competition is consuming a factor of magnitude less resources.
WASM DBs, maybe, especially as it continues to mature. Not Javascript.
One place where an interpreter + JIT language could be interesting is if it were sufficiently safe to allow user code into the query execution engine, such that the JIT could optimize it all together.
The only thing you can't do with JS today is share a heap across threads. You have SharedArrayBuffer. You have atomics. You don't need a shared address space.
There's a high performance database called "PostgreSQL" you may have heard about. It doesn't use threads. It uses separate processes and shared memory: just like standard JavaScript, with its service workers and SharedArrayBuffer.
If not sharing an address space is good enough for PostgreSQL, it's good enough for your TypeScript database.
The problem with shared-everything, unmarked, preemptive-parallel concurrency is that 90% of the time it gets used by people who don't know they shouldn't.
You can get parallelism with web workers and shove sqlite over there if you like, e.g. for running more intensive queries. Beyond that I kinda don't see much of a reason to use JS for databases, except maybe for isolation (e.g. via wasm).
> …competitively-performant… Care to explain competitively to what?
My conclusion from the project I'm working on is that, as of this day, there is no way to have both this so-called 20x performance improvement _and_ any kind of quality. Or security if whoever is running the agent has any token in an .env anywhere on the same file system.
We'll see in which direction the CTO takes this. My bet is not on quality.
Is it the AI or the people using it? Idk
I'm not so sure this is true anymore. It may have been years ago but... can you honestly say "the Bun project was fully AI written, therefore the quality is poor"?
Any concrete examples/proof?
``` In my experience, the worst bugs are the real-time bugs, which have to do with interactions with multiple threads. My approach to those bugs is to avoid making them. So I don't like threads. I think threads are an atrocious programming model. They're an occasionally necessarily evil, but they're not necessary for most of the things we use threads for.
One of the things I like about the browser model is that we only get one thread. Some people complain about that—if you lock up that thread, then the browser's locked up. So you just don't do that. There are constantly calls for putting threads into JavaScript and so far we've resisted that. I'm really glad we have.
The event-based model, which is what we're using in the browser, works really well. The only place where it breaks down is if you have some process that takes too long. I really like the approach that Google has taken in Gears to solving that, where they have a separate process which is completely isolated that you can send a program to and it'll run there. When it's finished, it'll tell you the result and the result comes back as an event. That's a brilliant model. ```
You could also have stuff like message ques going between them, the cost of passing data around is small then, you don't have do leave user space to put stuff in the mq's. But can you still call it "not having shared state"? I'd say yes, even though you do share memory and you do have the mutually accessible que. But I can see why you could argue otherwise.
I was right. Buried in the middle of the post is this tidbit:
> v1 collects synchronous and stop-the-world
Ah, there it is! I knew it!
Parallel garbage collection is a very hard problem. Years of experience and subtle implementation are required to get something like ZGC. A stop-the-world garbage collector will kill tail latency in many use-cases, especially for large programs. I'd say a good GC is the hardest part of a modern VM, even harder than a good JIT: not that a JIT is easy.
Show me multi-threaded JS with generational mark, sweep, compaction, etc. running in parallel with the mutator and I'll be impressed. (The smart thing would be to base it on the JVM or CLR. Doesn't count though.)
It's all so exhausting, this current programmer culture of doing the easy part of a system thing X and presenting your work, without qualifiers, as a complete and modern X.
Sure, sure, we can have memory safe C (just don't have any data races!). Sure, we can have an AI C compiler (just don't expect type checking). Sure, we can port SQLite to Rust (but don't expect it to be fast). Sure, you can one shot a Slack clone (just don't expect performance or security). Doing the easy part of a thing is not doing the thing! You can't trust a README's feature list these days.
To be fair, given that the README is obviously unedited LLM output, the authors might not have realized that their agents cheated and made threading easy by pessimizing the GC. The LLM certainly did though.
Now, maybe the JSC really is adaptable to a multi-threaded mutator world. If it is, great. But over and over, I've seen AI say "I will defer and charter $HARD_THING" and mean "I have no idea how to do $HARD_THING, so I'm creatively reinterpreting your request to make it easy". You have to be endlessly vigilant for LLMs subtly twisting your tasks into easy versions that might technically meet the requirements but they are less complete than you intend.
In addition to lifetime management, GC gives you compaction, pointer compression, and fast bump-pointer allocation that doesn't depend on being able to represent your lifetimes as nested arenas.
Modern GC is excellent. Replacing it with manual allocation isn't better, even with guardrails: reference counting is expensive, atomic reference counting doubly so, and free() itself is very far from free.
Sure, you can restrict lifetime shapes, but when you do that, people switch to allocating out of arrays and using indices as pointers, so you're right back where you started with respect to lifetime management.
So what are you saving? You're just replacing the high-performance concurrent mark/sweep microsecond-pause GC someone has written and debugged for you for free with custom convoluted logic that'll probably leak and run slower besides. Why would anyone want this trade?
The elevation of manual memory management to standard performance practice is a generational mistake this industry is making.
But if you're making a big fundamental change to a system, I do know that it shouldn't start with a single "+279,276 -4,272" PR. It starts with a small patch with the core of the change so that everyone can understand what it does and how it works. (I mean, ideally, a change like this starts with documentation, discussion, diagrams, surveys of existing implementations, etc, before you start writing code)
You don't cram everything into a single 270K line PR, even (especially) with an LLM, unless you specifically don't want anyone else to look too closely at what you did.
I considered writing such a JVM in Rust, following writing one in C (https://github.com/anematode/b-jvm) that could JIT WebAssembly code and run in the browser, but decided it would be too time-consuming.
Obviously such a VM would involve a lot of unsafe, but I'm wondering if you could establish some proper, compile-time-checked invariants that make things a lot safer, without the complicated sandboxing that modern JS runtimes use to make it harder for JIT bugs to escalate into full blown RCE.
Then it was removed it because it made garbage-collection a real mess (the JavaScript gc needs to walk through lots of C++ data, some of it may have specific requirements for destruction/finalization).
I hope it's better this time :)
Go build performant web app that has stop-the-world all the time.
No human has read or will ever read any of the code, nor was any human thought involved in its creation.
Everything is performative now. As long as you just keep your eyes closed and believe it all works, that's all that matters.
Agreed I would not want all Typescript users forced to use /this/ runtime, but if the TS team shipped tsc as "oh now it's uses a special fast JS runtime" (just like tsgo is a different runtime) I'd love to at least have the option of using the same special fast runtime in my own still-written-in-TS apps.
Seems I've either struck or a nerve, or miscommunicated, given the insta down votes.
But is Claude going to tell you "No, dear user, this project is going to follow an excessively simple and sub-optimal locking regime because experience shows that it is easier to write code than it is to reason about its exponentially-growing complexity" ?
Javascript shines when it's handling multiple concurrent IO operations, and concurrent operations can become very thread-like with async/await syntax. Multithreaded code in this context only helps with CPU-bound operations; but if I was doing something CPU-bound, I'd probably choose a different language.
One thing I wonder, does Bun (or Node) have a way to call into native code on another thread, but still keep single-threaded once back in JavaScript?
I love the idea of experimentation and innovation; I abhor the idea of it being dependent on Anthropic and their theft. I've never rooted for the Chinese labs more strongly than after seeing this.
If you can't even be bothered to write a non-slop PR description, it doesn't bode particularly well for the content of the PR itself...
I'd tap out here too if I was a maintainer. Even if the change was perfect, if you could not be bothered to write the PR description, I am not going to waste my time with it.
Edit: My bad, the PR is to a fork, in that case it's not our business how the PR description is written.
How are there not race conditions all over the place?
It's a very complex thing, but not impossible. I'm very impressed that any LLM can do this
This PR is an implementation of the design from https://webkit.org/blog/7846/concurrent-javascript-it-can-wo.... I think it would be really cool if JavaScript had true shared object multi-threading without compromises (SharedArrayBuffer, postMessage are not that). If we had both threads and structs, it’s likely the TypeScript compiler would never have needed to be rewritten in Go.
The title should be changed to clarify that it’s a PR to Bun’s JavaScriptCore fork and not the upstream WebKit.
This PR is scarier to merge than Bun’s Rust rewrite PR. There are a good number of benchmarks/stress tests, unit tests, and also TSAN runs and security scanner runs, but this is a more complex change than the Rust rewrite (yes, really). I’m also worried about syncing with upstream - today the “fork” is mostly a bunch of patches, but with this PR, changes to the JIT need to be reviewed for behavior when multiple threads are in use. Our best bet for this to move forward is figuring out a way for some constrained version to be upstreamed into WebKit proper, if that makes sense and if they’re interested.
And yes, the PR description is entirely Claude.
It makes me wonder how much of our software stack will become more malleable to big ideas and experiments in the future, like Filip’s idea here. Even if you don’t want to merge the code, it’s still an incredible existence proof that something like this could work.
The most important feature for a language runtime is reliability. It's the foundation, it should be boring. I need to know that the foundation is stable so that I can control the reliability of whatever's built on top.
AIs hallucinating a multithreaded JSC is not boring, it's scary.
AI is the epitome of the saying "if you want to go fast, go alone". This PR and the rust rewrite are incredible in scale and ambition. I still think theres a middle ground though of traditional committee-driven design with AI-driven iteration and POCs.
Barf
On a completely unrelated note, I wonder why Github is always down. Real mystery there.
“The bring-up log at the bottom is honest about what broke and what it took.”