Parent: #889 Related: #459, #484
Problem
#889 makes a failed call name its callee with JavaScriptCore's exact text on
both the tree-walker and the bytecode VM. The optimizing tier's native
runtime-operation dispatch (nativeOperationDispatch in src/vm.zig) is the one
remaining [[Call]] boundary that cannot, so a call that fails inside optimized
native code still reports the value-only wording:
TypeError: value is not a functioninstead of
TypeError: o.m is not a function. (In 'o.m()', 'o.m' is undefined)The tiers therefore disagree on message text for exactly the calls that got hot enough to be optimized — the class of divergence a green corpus hides, because test262 does not assert message text at all.
Why it was left out
jit.NativeFrame is an extern struct shared with generated code and carries no
owning bc.Chunk, so the dispatch entry point cannot reach chunk.callSiteAt
the way the interpreter loop does. Every call arm in nativeOperationDispatch
currently passes .none.
Required implementation
jit.NativeOperationMetadata already carries per-operation side tables that the
artifact builder fills in from the chunk — operation_names (consumed by
metadata.nameFor, which supplies call_method's property name) and
call_links. A call-site span table is the same pattern:
- add a
call_sites: []bc.CallSiteSpanparallel array toNativeOperationMetadata, populated whereoperation_namesalready is, from the originating chunk'scall_siteskeyed byNativeOperationDescriptor.origin(which is the bytecode instruction index); - expose
metadata.callSiteFor(operation_id)and pass the resultingInterpreter.CallSitefrom every call arm innativeOperationDispatchinstead of.none; - gate it: the existing
#889regression test insrc/context.zigasserts the identical text on the tree-walker and the VM, and the optimized tier must be driven to the same text by a warmed loop whose callee becomes non-callable.
No hot-path cost is involved: the span is read only after a callee has already turned out not to be callable.