Remove dead opcodes#21515
Merged
Merged
Conversation
Removes opcodes that are vestigial on both sides of the pipeline: * `VM_POP_ARGS_OP` (84): never emitted by the opcode compiler and has no runtime handler registered — a program containing it would crash. * `VM_JUMP_IF_OP` (65): a runtime handler was registered, but the compiler never emits it; all conditionals compile through `JumpUnless`/`JumpEq`. Removing it drops a live (non-tree-shakeable) handler from the append-opcodes table. * Wire format `StrictModifier` (5), `StrictBlock` (7), `DynamicArg` (20), `StaticArg` (21): never produced by the wire format encoder and never consumed by the opcode compiler; modifiers and blocks encode as plain `Modifier`/`Block` in both modes, and component args are encoded inline as hashes. Their only references were the opcode table itself, the interface types, and the wire-format debug printer. The wire format is version-locked (templates must be compiled by the matching compiler), so removing never-emitted opcodes is safe. Opcode numbers are not reused; the freed numbers just become gaps like the existing ones (93-94, 101-102, 104). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
📊 Size reportTarball size — dist/dev -0.03%↓
dist/prod -0.03%↓
smoke-tests/v2-app-template/dist -0.04%↓
smoke-tests/v2-app-hello-world-template/dist -0.11%↓
🤖 This report was automatically generated by wyvox/pkg-size |
Contributor
Author
|
no difference in perf in running |
kategengler
approved these changes
Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human notes
From bot exploration here:
It does, indeed, look like this stuff is unused. Is good to drop code we aren't using, as all code is liability.
AI Generated PR Summary and History
Removes opcodes that are vestigial on both sides of the pipeline:
VM_POP_ARGS_OP(84): never emitted by the opcode compiler and has no runtime handler registered — a program containing it would crash.VM_JUMP_IF_OP(65): a runtime handler was registered, but the compiler never emits it; all conditionals compile throughJumpUnless/JumpEq. Removing it drops a live (non-tree-shakeable) handler from the append-opcodes table.Wire format
StrictModifier(5),StrictBlock(7),DynamicArg(20),StaticArg(21): never produced by the wire format encoder and never consumed by the opcode compiler; modifiers and blocks encode as plainModifier/Blockin both modes, and component args are encoded inline as hashes. Their only references were the opcode table itself, the interface types, and the wire-format debug printer. The wire format is version-locked (templates must be compiled by the matching compiler), so removing never-emitted opcodes is safe.Opcode numbers are not reused; the freed numbers just become gaps like the existing ones (93-94, 101-102, 104).
Some archaeology on how these six opcodes became dead, from glimmer-vm history (where these packages lived before vendoring):
VM_JUMP_IF_OP(65)Dates back to the original
{{#if}}inlining (glimmerjs/glimmer-vm@5fcd6da23, Nov 2015). Its last real job was compiling{{#unless}}: evaluate the condition,ToBoolean, thenjumpIf('ELSE')to skip the main block when truthy ({{#if}}always used the mirror op,JumpUnless). It stopped being emitted in glimmerjs/glimmer-vm@8f5c02152 (Feb 2018), which introduced the structuredtryIfbuilder helper — emitting onlyJumpUnless— and reformulatedunlessas anifwith swapped branches. The runtime handler has been registered-but-unreachable for eight years since.VM_POP_ARGS_OP(84)Lived four days. Added in glimmerjs/glimmer-vm@c1ff46597 (Sep 8, 2017) to pop + clear the
Argumentsobject after static component invocations; removed — builder method, handler, and metadata — in glimmerjs/glimmer-vm@19340c9e8 (Sep 12, 2017) when frames took over argument cleanup. The enum entry was left behind, and the Dec 2018 opcode-TOML metadata generator (glimmerjs/glimmer-vm@b442d4e75) then faithfully cataloged[syscall.argspop]and began regenerating DEBUG metadata for an op with no emitter and no handler, which every later refactor carried along.StaticArg(21) /DynamicArg(20)Never actually wire format, even when alive: from 2016 on they were an intermediate representation inside the compiler. The JS compiler pushed
['static-arg', name, value]while walking a component's opening tag, andComponentBlockpartitioned them viaisArgumentand flattened them into the component'sargs: [keys, values]hash at serialization time — so they never appeared in final wire output, and no opcode-compiler or runtime consumer for the integer form ever existed in the repo's history. The producing code was deleted in the strict-mode precompiler rewrite (glimmerjs/glimmer-vm@8e11b9116, Sep 2020), which encodes component args directly as hashes; the types,isArgument, and debug-printer cases have lingered since.StrictModifier(5) /StrictBlock(7)Born dead. Reserved in glimmerjs/glimmer-vm@4c56c2164 (Jul 2019, "Lay groundwork for lexical scope") as anticipated strict-mode variants of
Modifier/Block.git log -S 'SexpOpcodes.StrictModifier'returns zero commits — nothing ever emitted or consumed them. When strict mode shipped in the 2020 precompiler it reused plainModifier/Blockfor both modes, and the reserved slots were forgotten.The common pattern: each op died during a compiler-architecture rewrite (2017 frames, 2018 builder helpers, 2020 strict-mode precompiler) that replaced the mechanism but left the opcode registry — enums, types, TOML metadata — intact, and later tooling preserved the corpses. This PR is the first pass auditing the registry against actual emit/handle sites.
🤖 Generated with Claude Code