js: witnesses, trait values, shared objects and the counts under Node (slice 3 of #63) #701
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Step 4 of epic #63 (JavaScript back end), slice 3 of
docs/design/JAVASCRIPT-BACKEND.mdsection 6: the rest of the language, part 2. Slices 1 (#678, PR #679) and 2 (#684, PR #694, landed asd515ae9d) are onmain: targetbrowser-js,compiler/src/backend/javascript/{emit,body,type,natives,writer}.trb,runtime/javascript/{core,int64}.mjs,tools/conformance.sh --js,tests/conformance/js.allow, CI jobconformance-js.Source
docs/design/JAVASCRIPT-BACKEND.mdsection 6 row 3, section 2.6 (generics, traits, dynamic dispatch) and section 4 (memory:Close, copy on write, identity).docs/design/DESTRUCTORS.mdsection 2a (when exactly a release happens),docs/design/DESTRUCTORS.mdsection 10 (R1, R3).compiler/src/backend/c/body.trb(CallWitness,TraitValue,Retain,Release,MakeUnique,releaseStatement,dropFunctionOf) andcompiler/src/ir/ir.trb(WitnessTable,WitnessSource,Instruction).Goal
The emitter, which today reports these as unsupported findings, handles:
signature.witnessesis not empty takes the tables as leading arguments (parametersOf,emitCall);Callwithwitnessespasses them;CallWitnessisw.m<k>(self, ...)on aWitnessSource(rootandsteps, thenestedtables of a supertrait).constobject perWitnessTable, created once, with the same property names in the same order for every table of a trait (m0,m1, ... formembers, one property per slot; a slot ofFunctionId(-1)isnull), plusnestedanddrop.TraitValueandObject(bounds). The pair of the value and one table per bound.SharedObject. A class pershared typelayout whose identity is the JavaScript object.Retain,Release,EndOfScope,ClearandMakeUnique(today all printed as nothing), and the drop function that runsclose().Compiler only. Everything the program does not use stays absent from the output (a program without
Close, without aMakeUnique/Writeof a counted type, or without traits emits none of this).Decided by the loop
Each follows the record or the C back end; none needs the owner.
membersbecome propertiesm0 ... mNin table order;nestedis an array of tables (nullforNone);dropis the drop function of the target (ornullwhen the target holds nothing counted). All tables of one trait are written by one generated constructor function so they share a hidden class, which makesw.m3one inline cache (section 2.6).{v, w0, w1, ...}, onew<i>per bound in bound order, the same shape as the C back end'sdatapluswitnessMemberNameOf(i); a call through boundiiso.w<i>.m<k>(o.v, ...). The record writes{v, w}for the single-bound case, which isw0; this issue records the generalisation. Narrowing to a supertrait iso.w0.nested[j].rcfield, initialised to 1 by its constructor, if and only if it is (a) the base of aMakeUniqueor of aWriteanywhere in the program, or (b) a type for whichir/closing.trbanswersClosing.holding(it can hold aCloseobject). It is one whole-program flag computed by one walk inemit.trb, passed tobody.trbandtype.trb;Retainisx.rc++,Releaseisrelease$T(x)which decrements and at zero runs the drop. ARetainorReleaseof any other type prints nothing, as today.MakeUniqueof a counted base clones whenrc > 1and decrements the original, using the same generatedclone()theCopyof slice 2 already uses.Closeorder.release$Tcloses the held objects in the order the C drop function does (fields in reverse declaration order, elements of aFixedArrayin reverse, then the object's ownclose()first for ashared type); readdropFunctionOfand DESTRUCTORS.md section 2a and copy the order, not the mechanism. Ashared type'sclose()is called at most once (the drop clears the field).try/finally. A panic runs noclose()(section 2.7); the drop is plain generated code.Files
compiler/src/backend/javascript/body.trb:emitCall,parametersOf,emitInstruction(CallWitness,TraitValue,Retain,Release,EndOfScope,Clear,MakeUnique).compiler/src/backend/javascript/type.trb: classes for shared objects, thercfield,clone()for counted aggregates,release$Tand drop functions.compiler/src/backend/javascript/emit.trb: witness-table constants, the whole-programrcflag, ordering of module-level constants.runtime/javascript/core.mjs: only if a small helper (a sharedreleaseof a bare counted object) is needed.tests/conformance/js-witnesses-close.trb(new) with.expectedand.exit, andtests/conformance/js.allow.docs/design/JAVASCRIPT-BACKEND.md: row 3 marked done, "What slice 3 left out" paragraph,docs/regenerated astorb docsrequires.Tests
tests/conformance/js-witnesses-close.trb, printing only text andInt(no list,Showor map, which need slice 4): a generic function with a trait bound called with two types (CallWitness), a trait-typed value built from two types and called through (TraitValue,Object), a supertrait narrowing, ashared typewithclose()that prints its name, closed in reverse declaration order at scope end, on an earlyreturn, when held by a record field and by an array, and a copy-on-write case (a record kept by two names, one written in place; the other keeps its value). Passes on the C, VM and JavaScript legs with the same.expectedand.exitfiles..expected,.stderrand.exitfiles joinstests/conformance/js.allow:traits,trait-values,bound-methods,plain-bound,generics,generic-trait-members,trait-constants,source-trait-value,trait-typed-literals,implementation-trait-arguments,entry-cell-trait,shared-top-level-const,destructor-scope-end,destructor-early-exits,destructor-fields-and-lists,destructor-patterns-and-temporaries,destructor-conditional-temporaries,destructor-using,destructor-slice-concrete,slice-close-generic.A program of that list that still fails because of a construct of a later slice (a list or map native,
Show, a task) stays off the list; the PR body lists each such program with the finding or the line of output that names the later slice. Programs with.allocationsfiles are leak-style: their allocation counts are a C-leg check and are not compared on the JavaScript leg, but theclose()lines they print must match.js.allowis removed; the existing JS programs still pass.Acceptance criteria
js-witnesses-close.trbpasses on the C, VM and JavaScript legs; the close order and the copy-on-write result match the C leg byte for bytejs.allowgrows by every program of the list above that passes, at leasttraitsortrait-values, and at least one ofdestructor-scope-endordestructor-early-exits; each program left off is listed in the PR with its reasonCloseor counted writes produces the same JavaScript as before (norc, no tables): pinned by an unchanged output ofjavascript_first.trbtorb format --checkandtorb docs checkgreentools/check-commits.shclean;sh tools/gates.sh aand theconformance-jsjob green in forge CI (CI only, no local bootstrap or gates)Seed
Compiler only: no syntax change, no new native, no std name the compiler looks up, no change of the manifest, no
Architecturecase.seed/is untouched. One PR; one Conventional Commit per logical change (feat(js): ...,test(js): ...), expect two or three.Out of scope
Slices 4 to 8:
ListStorage,isSameand the kernel natives (4), floats andlibm(5), structured control flow (6), tasks,Suspend, frame release and cancellation (7),.nojsmarkers andtorb test(8). A minifier, source maps.Dependencies
#684 (slice 2, landed as PR #694,
d515ae9d).Part of #63 (epic; do not close it).
[loop:torbscript] ready: filed just in time from the design record's slice table (row 3) after slice 2 landed. Technical choices are recorded in the issue under "Decided by the loop".
next: ready
[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T01:31Z
[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: the worker run ended without a result (the worker runtime refused its oversized output log); no branch, commit or PR was pushed, so nothing is left to pick up. The item is still
ready; the next worker starts from main and keeps its command output small.next: implementation
[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T02:20Z
[loop:torbscript] implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: worker interrupted by a gateway restart after opening PR #703 (head
950140cd, CI success, mergeable, argus requested). Release of the claim.next: review
[orion] PR #703 merged 2026-10-30 22:10Z (argus). Slice 3 is in main; no after-merge steps or deploy in the PR. Removed the stale ready label; the issue is closed.