Repository navigation
Conversation
|
Preview build of 13643a4: |
JSModuleNamespaceObject::layExportOverride() stores a value in the binding that an export resolves to, for an owner. The record that declares the binding keeps the owners of each of its bindings in the order in which they stored, and what each of them found in the binding. removeExportOverride() ends one owner: the owner whose value shows gives back what it found, and any other hands that to the owner that stored next. One owner of a binding takes two elements of the record's table and no cell. An array is made for a binding when a second owner stores in it, or when its owner is set aside. AOT::Modules keeps the owners of a variable of the program in the same way. The mock of a file owns what it lays, and AOT::layExportOverride() takes the owner of a host. overrideExportValue() is unchanged. overrideExports() had no caller and goes.
robobun
force-pushed
the
robobun/929034ed/export-override-owners
branch
from
November 11, 2026 11:06
9c18661 to
13643a4
Compare
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.
Problem
spyOn) stores back its own copy of what it replaced, andexport * fromlets several namespace objects share one binding.bun testthen reads"mock of inner"in the next test file. The compiled runtime has the same fault (AOT::Modules::endMockLaidOverFile).Fix
JSModuleNamespaceObject::layExportOverrideandremoveExportOverridetake an owner cell. The declaring record keeps the owners of a binding in order, and what each one found (ExportOverrideLayers).AOT::Modulesdoes the same for a program variable.JSTests/modules/bun-owners-of-an-export-override-end-in-any-order.js.overrideExportValueis unchanged.Background
AbstractModuleRecord: 8 bytes per record in every program. Considered a hand-over in Bun: spies and compiled modules stay wrong.Downsides
sizeofstays forAbstractModuleRecord(320),JSModuleRecord(416),JSModuleNamespaceObject(72) andVM(110,872).AOT::Modulesgrows by 16 bytes,.textof releasebunby 13,568 with the Bun side.spyOnplusmockRestoreof a namespace export: 5,679 instructions, from 4,814 (no JIT).Notes
The rules. Each overridden binding has its owners in the order in which they stored. Each owner has what it found in the binding when it stored.
layExportOverride)removeExportOverride)setExportOverrideAside)A binding that had no value yet when its owner stored cannot go back to having none (DFG and FTL drop the TDZ check). The end returns
HadNoValueand the host decides what to store.didInitializeExportUnderOverriderecords the value that the module body stores later.exportFoundByOverridereads what an owner found.Storage. The record that declares the binding gets one object under the private name
exportOverridesat its first override. The object has two elements per binding, at twice the scope offset of the binding. One owner takes the two elements (the owner, what it found) and no cell. A second owner, or an owner that is set aside, makes an array of three elements per owner. The table stays with the record after the last override ends.export * as ns. The*namespace*binding of a record is empty untilgetModuleNamespace()runs.layExportOverrideruns it first, asoverrideExportValuedoes, so the owner finds the namespace object.Compiled runtime.
AOT::Modules::tryReplaceExportkept the first value that a mock replaced inLoadedModule::variablesBeforeMock, andendMockLaidOverFilestored it back. That table now names the variables only, and is the owner of what the mock laid. A host owner (a spy) comes throughAOT::layExportOverride.takeOwnersHandedByMockstells the host which owners the end of a mock handed a value to. Exports that the runtime keeps outside a variable of the program (captured exports of a builtin module, a namespace handed on, an export behind a star) keep their storage:AOT::layExportOverridereturns false for them.Bun side. oven-sh/bun#48621.
Removed.
JSModuleNamespaceObject::overrideExportshad no caller in Bun.Base. The branch starts at 264cf6d, the commit that Bun's main pins, so that the preview build works with Bun's main. It merges into main without conflict.
What the test covers. Three namespace objects that export one binding (
export *,export { a as renamed }). The owner that stored last ends first, and ends last. An owner that stores again. An owner that is set aside, alone and under another owner. A value that the module assigns meanwhile. Two names of one binding. A binding that has no value yet.export * asbefore the namespace object exists. An export that has no binding.Checked against a model. The rules ran against an enumeration of mock, spy and unmock sequences (about 1M sequences, 0 wrong answers). The table form with one owner ran against the array form in a random walk of 4.2M steps, with no difference.
Numbers. Release builds of
bunwith the same flags, 873ab3a against this change on 873ab3a, each with its side of Bun. They are from before the rebase onto 264cf6d. Instructions are user-mode counts (perf_event_open), the minimum of 3 runs.sizeofAbstractModuleRecord/JSModuleRecord/JSModuleNamespaceObject/VMsizeof(AOT::Modules).textofbunoverrideExportValuevm.SyntheticModulesetExport, per callspyOnplusmockRestoreof a namespace export (no JIT)resolveExportcalls for one mock of 100 exports and its end