Announcing PVM2: Reimagining PVM towards standard RISC-V

Background

PVM is the instruction set architecture (ISA) of PolkaVM. This is the planned ISA to be deployed on the JAM Chain, advertised to be fast. In March, we started Grey (later known as JAR). JAR’s virtual machine JAVM is based on PVM ISA, and we managed to accomplish a 2x speed up for many of our PVM workloads compared with PolkaVM.

Our design has diverged a lot from JAM, challenging many of the JAM’s design rationales. We have since had, notably, a capability-based system and a real kvm microkernel which give us some impressive performance results and security properties. But until recently, we still kept PVM ISA almost unmodified.

The PVM ISA is the part we think that is also worth some deep thinking for us. PVM ISA has an entirely custom encoding definition. So we asked ourselves a simple question: do we really need it? If we move PVM towards a mostly standard-compliant RISC-V, can we get the same performance?

Specification: Defining PVM2

So we designed PVM2. A new ISA that is kept as close to the RISC-V spec as possible. How we define it is like this. We define a new base ISA. Supposedly, this will be the only thing we want to modify. Then we apply RISC-V extensions cleanly on top.

Our entire base ISA is defined as a short differential from RV64E, with just the following changes:

  • Memory address space
  • New meaning of pc
  • Disabled auipc, jalr (and c.jalr).
  • Standard-compliant custom-0 RISC-V instructions, trap, ecall.jar, ecalli.jar, br_table and fallthrough.

That’s basically it.

We then apply unmodified standard RISC-V extensions: m, c, zbb, zba, zbs, zicond, zicclsm.

Rationale: Future-proofing the spec

Some of the designs in PVM is questionable, or at least, debatable. An example is bitmask, which bloats the binary size by 12.5%. Supposedly, this is for random access to the program. Yet, the new gas metering requires a pre-validation round, completely defeating the purpose. There’s no flexibility in any of this: as an ISA spec, you either have it, or you do not. The middle ground is the worst of all places.

One of the rationales for PVM2 is to side-step this. We use the standard whenever possible. Avoid reinventing the wheels when it’s not necessary.

A mostly-standard RISC-V ISA also has significant advantage in its tooling: if LLVM ships any optimizations, we get it immediately. No bikeshedding with the transpiler to “re-support”. In addition, even our custom-0 instructions are defined in a standard-compliant way. This means we can easily utilize, for example, Rust’s asm macro, in a way that is not straightforward on PVM.

Our design also allows us to support new RISC-V extensions at ease.

Findings: You don’t need PVM

Our findings are quite clear: you don’t need PVM – we implemented the PVM2 ISA for JAVM, and managed to get a recompiler that is as fast as the old custom ISA. Our benchmark results are as follows.

Benchmarking comparison

We measured recompile + execute time. JAVM (PVM2) runs as fast as JAVM (PVM) on most workloads. And JAVM (PVM) itself is around 2x faster than PolkaVM.

In-house delta

The below table shows the in-house delta between JAVM (PVM2) and JAVM (PVM).

Binary size comparison

The binary size of PVM2 is also competitive. This is probably mainly due to PVM’s insistence of keeping bitmask, a 12.5% overhead. The reason that PVM2 can effortlessly enable a few more standard RISC-V extensions also helped.

Links

Is this intended as constructive technical feedback relevant to JAM/PVM, or primarily promotion of a separate competing project?

On 28.05.2026, this post becomes the subject of a censorship attempt by Polkadot mods. The censorship decision has since been reverted, and here we would like to provide our recollection of what happened.

Timeline

  • Around 16:00 UTC, a Polkadot mod posted the following message on this forum post: “Is this intended as constructive technical feedback relevant to JAM/PVM, or primarily promotion of a separate competing project?”
  • Several minutes later, we received a system notification from Polkadot Forum, that the post is marked as Spam.
  • The post was censored, became non-visible even to ourselves.
  • 8 hours later, probably due to the backlash from Twitter, we found out that the moderation censorship decision was reverted and the post is back to normal.

Our Statement: An echo-chamber is the very thing that will bring Polkadot to irrelevancy

Polkadot itself is not developed in a vacuum. Polkadot’s BABE is derived from Cardano’s Ouroboros. GRANDPA’s GHOST took heavy inspirations from the discussions in Ethereum’s Casper FFG. BFT from Cosmos (Tendermint). Various VRF usage has heavy roots from Algorand. NPoS is a refinement of DPoS which was pioneered by EOS. Tezos began on-chain governance much earlier than Polkadot. And finally, parachain is essentially an improved version of Ethereum’s earlier abandoned sharding design.

The observation couldn’t have been more clear: If you ban even technical discussions about competing projects, then Polkadot can’t even exist.

The issue wasn’t apparent 2 or 3 years ago when Polkadot still led in technology. Competing projects were generally worse off. This is not the case any more. Monad, Tempo, etc, dwarfs Polkadot Hub / Revive for its EVM execution performance, exactly as we predicted a year ago. Now, with our new benchmarks on PVM2 as specified in this post, we also know that PVM itself, as advertised by Parity/W3F as the “top-performant VM”, is probably also a sham.

You aren’t leading in tech any more. You can of course continue to do what you’re doing today – feel threatened and censor information. But your censorship will not change facts. If JAR/JAVM is 2x faster than PolkaVM, it will continue to be 2x faster regardless of your moderation decision.

If you don’t allow discussions about why “competing projects” are faster than you, the loss is on you. Praying that the “Parity/W3F god” will do all the work for you is of course still a strategy (I use the term “pray to the god” deliberately, because that’s essentially what this community is doing right now), but it should be apparent that it’s not a good strategy especially for something that is supposed to be “decentralized”, and Parity/W3F does not have a good track record of being correct.

JAR Chain and JAM Chain are both protocols. In a healthy decentralized community, open competition should have been allowed. For example, as a principle, the Polkadot community should decide the technical stack of its future – JAR Chain or JAM Chain. Not a decision made by Polkadot insiders and mods.

JAR Chain itself is coinless so we wouldn’t have been competing with any coins regardless, but labeling us as a “competing project” is exactly how you will get an actual competing project for Polkadot. And you’ll be happy to know that we’ll indeed be happy to “compete”. After all, we stay lean, and with software development itself now essentially costs 0 with the emergence of agentic coding, we have the financial freedom to pursue what we want to build indefinitely. Unlike Polkadot, there’s no pressure for us to urgently “turn a profit”.

I want to end this with a quote from Gavin:

So I’m curious - since you’re suddenly so against echo chambers and censorship, does this mean you’ll unban me from your Element channel? Or is it only “censorship” and an “echo chamber” when it’s applied to you? :stuck_out_tongue:

Anyway, I genuinely wish you luck with your project. I’m looking forward to adding your VM to my benchmarking harness to cross-compare in a fair way.

PS: You’ve intrigued me with your numbers so I transplanted your ed25519 benchmark into my benchmarking harness in PolkaVM, since that one was showing a big difference.

I got a blob of exactly 43284 bytes using the current PolkaVM toolchain (so smaller than your 94136 bytes, never mind the 229041 bytes you were getting previously; I could probably get it even smaller if I messed with inlining thresholds).

I also checked the recompile + execute times of that benchmark, and I measured ~1266us for PolkaVM (so it was indeed close to what you measured). Fortunately, like many things in PolkaVM, the code in question is still not fully optimized, so after spending 10 minutes working on it I got it to ~896us, which I guess is still slightly slower than your ~644us, so fair enough; that’ll have to stay as-is until I have more time to optimize it further. Although, if I disable the full gas cost model and use a simplified model (like you did for PVM2) then I’m getting a time of ~339us, so only two times faster than what you’re getting. (:

Hi Wei,

The forum will always welcome constructive feedback or discussions regarding the progress of the network. if something can be done better, it should be proposed for sure.

You’re right that Polkadot built on ideas from Ouroboros, Casper, and the rest. Good protocols borrow. But notice that none of those were imported wrapped in contempt for the people who’d receive them. Borrowing well and dunking are not the same activity.

Bring the JAR architecture and let people poke at it. If it holds up, plenty here will say so out loud. Hold constructive discussions, not discussions aimed at putting the network down. Competition that sharpens the tech is welcome and always will be.

But if the goal is mostly to tell people they’re praying to a false god, you’ll get the engagement but very little of the actual scrutiny that would prove your point. That, with all due respect, would be a waste of work that sounds like it’s worth taking seriously.

This is a constant problem with your benchmark. You’re always trying to cheat your way in the benchmark for PolkaVM. The recompiler has a bytecode throughput. If you tweak the LLVM inline to get a vastly different blob size, the recompile process will of course be vast different. We can also tweak our LLVM inline parameter (and in PVM2 it’s much much easier) and get smaller sizes.

If you tweaked inline to get half the blob size (which we can also do) and still 40% slower, that means we’re 3x faster than PolkaVM. But we won’t claim those premature data.

It’s interesting that several months ago you told us that your interpreter is “unoptimized”. And now you claim your recompiler is “not fully optimized”.

The “simplified model” you mentioned is also incorrect. The current implemented “simplified model” in PolkaVM is the “naive” gas metering, which is far from a production-grade spec. You’re welcome to adopt the single-pass pipeline simulation gas metering we developed for JAR Chain.


But this is missing the tree for the forest. If you actually read the top forum post, what our benchmark primarily shows is not about PolkaVM vs JAVM. It’s true of course that JAVM is 2x faster than PolkaVM, and this has been an established facts for over a month. In fact, PolkaVM is so slow that we aren’t even using it as a target any more. (I’m sure if you adopt the optimizations in our old code pre-PVM2-migration, you can catch up on the single-vm benchmarks, but you’ll never catch up on our large multi-vm benchmarks – we have a much more optimized capability-based architecture that it’s not possible for you to match unless you’re open to a full overhaul of the JAM design.)

What we’re showing is, rather, the entire PVM ISA is unnecessary. If you read our benchmark data, we mainly compare in-house – our own JAVM (legacy PVM, but already 2x faster than PolkaVM) vs JAVM (PVM2). We get competitive results for JAVM (PVM2). There’s no significant benefits to the legacy PVM ISA. We can get comparable performance and binary size using mostly standard RISC-V ISA. There are enormous benefits following a standard instead of handroll things, and that’s the direction (PVM2) we’ll go with in JAR Chain.


This is honestly a trend we’ve been repeatedly seeing in Polkadot development. A lot of over-engineering without sufficient data to back it. Last year’s EVM debate was another example. Now in retrospect everyone will just look at the real-world data and laugh.

(Disclaimer: this should be obvious, but, any opinions/statements expressed here are purely my own and do not reflect those of my employer)

My whole point was that I’m NOT trying to cheat here by messing with the inliner. :stuck_out_tongue: Let me paste you one of your very own commits:

perf(pvm2): drop inline-threshold from 275 to 265 for build_pvm2
LLVM’s inliner has a discrete cost cutoff: a specific large function
gets inlined into ed25519 once inline-threshold crosses ~265-270,
and the inlined+unrolled body bloats the ed25519 PVM2 blob from 42KB
to 92KB. The same threshold-crossing also lets ecrecover deduplicate
its single-use callsites (97KB at it≥265, 107KB below). 265 lands
in the narrow window where ed25519 stays pre-cliff (42KB) AND
ecrecover stays post-cliff (97KB) — both at their respective local
size minima.

Blob size (PVM2):
workload it=275 (was) it=265 (now)
ed25519 91830B 42198B (−54%)
ecrecover 97646B 97680B (~)
others unchanged

Anyway, the reason why I’m interested in adding your VM to my benchmarking harness is precisely because I’d like to know where I stand compared to the competition in a fair way so that I can improve things, but e.g. I can’t really rely on your numbers considering you’re acting in bad faith.

Here’s my invitation to you (and anyone else): I have a benchmarking harness and a set of benchmarks in the PolkaVM repository. I welcome any and all PRs adding new benchmarks (or other alternative VMs) which make PolkaVM look bad. I will merge such PRs and publish the numbers, even if it gives the current PolkaVM a bad look.

I have very little interest in marketing PolkaVM; my only objective here is to make the best possible VM for JAM. Which is why I’m not (please excuse the unprofessional language) making a new forum post every time I fart, and I’m not taking any and every opportunity to shit on my competition and put it in as bad of a light as possible, and I’m certainly not on a revenge arc against a company for which I used to work for but don’t anymore. (:

It’s not incorrect. If I set the gas costs appropriately for each instructions (they’re by default set to 1 in the repo, but I do have them calculated to be secure, and the performance is exactly the same whether you set them to 1 or set them to anything else) then it is correct and secure. The issue here is this though: this is a tradeoff. The fancier you make the gas cost model the cheaper the gas will become, at the cost of paying more to calculate the gas costs. Your simpler gas cost model (assuming it’s secure, which I don’t know if it is) is just you picking a different point on the tradeoff curve, rather than the black-and-white thing you’re making it out to be.

Is that what Claude’s telling you? Of course it’s possible for us to match (and exceed) whatever you’re getting, and it doesn’t require anything close to a full overhaul of the underlying JAM design. :stuck_out_tongue: One consistent misunderstanding you’re having is that you’re confusing implementation-details with hard constraints imposed by the spec, and you’re assuming whatever we have implemented in PolkaVM is the final design and/or the final implementation. It is not.

So basically, you created a new ISA not compatible with PVM (which stands for “Polkadot Virtual Machine”, as per Graypaper, with “Polkadot” being a registered trademark of W3F AFAIK) to be executed on your very own chain, and for that matter, your VM is not compatible with JAM nor with Polkadot, and you decided to name it… PVM2? I don’t get it.

It’s interesting you aren’t addressing any of the “hard truths” I presented, but just quickly waived it and continued on with what “could have” been.

I think this is our difference: we don’t present a hollow roadmap, and then mislead the community for years. We present what we have implemented and working.

Someone already did that for your interpreter: Benchmark: PolkaVM vs revm syscall overhead analysis — 26-98x slower on storage/hashing, faster on pure computation · Issue #363 · paritytech/polkavm · GitHub

Do you still remember what you told the community about PolkaVM interpreter last year launching on Polkadot Hub? That’s what happens when you constantly try to cheat the benchmark numbers.

For recompiler, you get this in reverse. We already have the benchmark done in our project in a fair way. And we presented with hard numbers. It’s up to you to submit PRs to our repos to disprove it.

And it’s quite interesting that you said you “have very little interest in marketing PolkaVM”, yet you seem to be so fixated on arguing over the benchmark. 2x faster than PolkaVM is an established fact since weeks, and we just included that as footnote. Let me note to our reader: our main finding is that the PVM ISA is not necessary which you completely skimmed over.

It’s actually incorrect. Why do you think Ethereum folks spending years tweaking gas metering numbers? Get it wrong, and your chain may go down.

But anyway, what I mentioned more is on the benchmark number: you can’t compare naive gas metering with a production-grade metering. Either adopt JAR style single-pass pipeline simulation, or put a temporary naive gas metering route into JAR’s codebase and benchmark against that.

Don’t always try to cheat on your benchmarks. It doesn’t work. Have you noticed that PolkaVM is under development for 3 years and you still have very little use outside of Polkadot? Because people notice when you’re cheating.

You haven’t actually understood our specification / architecture, do you? I don’t plan to explain our new architecture in detail in this post, but we do plan to do that in separate posts in the near future.

You actually can’t match our benchmark unless you do a complete redesign of JAM. Same as the reason why you didn’t choose to improve on Wasm but switched to RISC-V.

Of course, you’re welcome to prove us wrong by showing us a real implementation. The community sees pass through your “hallow roadmap” trick.

In Rust community, “PVM” stands for “Parsing Virtual Machine”.

We’re within our rights to name it PVM2. This is an established naming convention for ISAs.

For my interpreter? If you’re going to link to something you should consider reading it first. :stuck_out_tongue: Anyway, here, let me quote you directly from that issue:

PolkaVM v0.30, BackendKind::Compiler

Yeah, we’re slower there when running with the recompiler. It’s a known issue caused by suboptimal implementation of reads and writes to/from the guest memory (which, spoiler alert, I’m in the process of fixing with a complete rewrite of my sandbox implementation).

I’m not? It’s you who’s constantly making new threads about how much faster you are, how crappy everything else is, and how only your solution is the only good one. (:

You’re completely wrong here. As long as the gas costs for each instruction (even with a very simple, naive gas cost model) are set correctly (i.e. it’s impossible to use up more compute resources by using that instruction than what the gas cost suggest) then it is secure and “production-grade” (whatever that means). The only difference is that your gas costs are now very expensive, because you had to make the cost of each instruction the absolute worst-case, and your gas cost model is very far off from how the hardware actually works.

You ask me why I’m not addressing any of the “hard truths”, and here’s my answer - there’s no point when every argument you make is in bad faith, and your posts are always full of gross misunderstandings (like here with the gas cost model) and full of hyperbole. You aren’t interested in having a constructive discussion. You only care about putting yourself (and your, or rather - your Claude’s work) on a pedestal, and put everyone else down.

Right, it’s the recompiler. But my point stands.

I’ve explained that your argument breaks down completely at least for your “naive” gas model currently in PolkaVM. As you seem to want to argue in bad faith by accusing others are arguing in bad faith, let me address your next point first.

You have constantly been making this arguments that everyone else is presenting things “in bad faith”. Remember how you did that last year about EVM and that costs Polkadot community millions?

Keep doing that. Not my problem.

But anyway, we’re not presenting the arguments to you. We’re presenting the arguments to everyone who plans to use Polkadot and PolkaVM. Remember one of the prime argument you made about adopting PolkaVM on Polkadot is that PolkaVM is fast? Teams called you out, and actually, we have a lot more evidence that your benchmarks are rather a gross cherry-pick with only the workloads that favor you. We also presented our findings today that the entire PVM ISA is unnecessary.

When teams need to use something and investors need to spend serious money, they take a look at the hard truth, and they verify it themselves. Not your waiving on the hallow roadmap (“we don’t have it yet, but we’ll have it in the future”) or discrediting others saying they’re “bad faith”.

As we told you already and in multiple occasions. We stand by our hard truth. We have verifiable data. So we’ll continue to present them. And by the way, we aren’t even saying that what we developed is already complete or performant – we also have a lot of rooms for improvements (and yes, that means our bench, while already 2x of PolkaVM, can still improve). What we’re saying is just, the custom PVM ISA you’re developing is a dead end because you can get equally performant architecture with standard RISC-V.

It’s not our problem if you want to label every critical comments as “gross misunderstanding and full of hyperbole”. Actually, based on what you and your team have been costing the Polkadot ecosystem in the past years, I take it as a compliment.

Because some random guy published a single version of the so-named crate nine years ago? :person_shrugging:

Okay, not my business, I believe W3F has a legal team if they want to pay attention to it.

The good thing is you’re building a VM, and it’s fast (although after you brought back auipc/jalr it’s rather a standard RISC-V with a couple of vendor extensions than a new ISA).

The bad thing is that it seems the only purpose of your VM is to compete with PolkaVM, rather than to perform any real on-chain execution. The code quality in the PR I linked above is nowhere near PolkaVM. Those multiline slop comments from Claude to itself were most probably produced by something like “Claude, make it faster than PolkaVM, make no mistakes”.

A VM should not be just fast, it should be safe and supportable as well.

Happy to take it on. We have the financial resources to defend our rights.

And we’ll be happily publishing everything we can publish in the process. The community has been asking for transparency from W3F for a long time. This will actually be a good opportunity to reveal more information.

Let me remind you, PolkaVM just recently had to fix a security bug and yank two consecutive releases 0.32.0 and 0.33.0.

Yes, you heard it right – this has gone into PolkaVM releases. No CVE number. No public communication. If someone has been really using PolkaVM in production other than Parity, they’ll be in a bad time. Fortunately we don’t have any yet.

Since you’re talking about legal and you seem to be claiming that “the code quality in the PR I linked above is nowhere near PolkaVM” – better back it up by objective data. Otherwise, this breaks comparative advertising law: comparative advertising is allowed as long as it is objective and factual. We backed up all our claims by benchmarks and hard truths, which even Jan himself has to (partially) confirm.

Fortunately, we aren’t as pity as you and won’t throw random legal threats around. (:

If you had actually read our post, you’ll know that the post’s main thesis is that, based on our benchmarks, we believe the PVM ISA itself is unnecessary. It wasn’t about PolkaVM vs JAVM, or JAM Chain vs JAR Chain. But since you have to make it, then here’s a comparison chart we made a few weeks ago.

By the way, unlike PolkaVM which has been in development for three years, we’re a young project that was started 3 months ago. We haven’t made any release yet, and are of course still in development. The difference for us is: we don’t try to convince the community about any of our safety / security criteria through blind trusts to any humans or organizations. As you seen from the bugs PolkaVM has to pull from releases, and critical security issues on Polkadot, blind human trust is extremely fragile. Instead, we prove our security through our architectural design and objective means. We have an important principle for JAR: correct by construction. If you say 49% of our inspirations come from JAM, then 51% of our inspirations actually come from seL4 microkernel and formal verification. This is why we spent a long time designing our capability-based system and the data-flow principle.

Even Vitalik mentioned this as a primary trend in blockchain development:

Provably bug-free Ethereum. This is a goal that all cybersecurity researchers would have thought is absurd and impossible, up until roughly 6 months ago. Now, it’s on the cusp of being possible, thanks to AI-assisted formal verification. So we should be frontrunners in doing this.

I think you’ll see more and more chains taking up approaches similar to us and what Vitalik mentioned, and less and less chains will have the anti-AI approach that Polkadot right now is experiencing. Hell, you may even see JAM Chain adopting JAR’s capability-based system or data-flow principle some day, if not for the fact of JAM Prize that, with the now already closing M1 milestone verification, they’ll now make implementors’ time miserable if they do large overhauls like this.

Anyway, in blockchain, you’ll eventually have to be open source anyway. Keeping things closed source like JAM is doing right now won’t fend out “competitors”, but will just make your own stuff not meaningful in the meantime. So even logistically speaking, we’ll always welcome competition, we always publish our design as early as possible, and we don’t fear to develop in the open. (But as I said, JAR is coinless and it does not directly compete with “coin-ful” chains, but you seemed to be want to label us as a “competitor”, so we’ll be happily taking on the hat.)

Small update: the binary size comparison table is now updated to compare the correct thing – actual code sizes. Previous version contained a bug where we generated correct but uncompressed images with a lot of zeros.

The fixed version shows an even more significant gain of PVM2. Note: PVM2 is standard RISC-V (+c). So this really reaffirms our conclusion – the custom PVM ISA is unnecessary and actually much worse than PVM2 (standard RISC-V). PVM2 (standard RISC-V) beats PVM on binary size, and performance is better or equivalent.