Part of #856 (perf epic). Depends on #856-F4 (typed locals). Drives the count-primes (28×) and array-methods (23×) gaps.
Summary
In compiled mode, every array element get/set emits a multi-way isinst type-dispatch ladder inline at the call site, plus index-boxing and element box/unbox — even when the array's element type is statically known (boolean[], number[]). The element store is backed by List<object>, so primitives are boxed.
Evidence (emitted IL)
isPrime[j] = false expands inline to:
isinst List`1<bool> → if yes: SetArrayElementBool
else isinst $Array → $Array::Set(int64, object) (index + value boxed)
else isinst List`1<object> + _frozenObjects CWT probe → SetArrayElement
else isinst $Undefined / null → throw TypeError("Cannot set properties of ...")
else SetIndex(object,object,object)
This ladder is duplicated at every element site. countPrimes compiles to 1196 bytes of IL for a sieve. Reads mirror it (isinst List<bool> → get_Item → box Boolean → IsTruthy).
Bonus O(n) trap: the push-normalize path's IList fallback (countPrimes IL_0086, arrayMethods IL_0074) copies the entire list element-by-element into a new List<object>. Harmless when the array is already List<object> (it short-circuits), but a latent O(n)-per-call hazard if that branch is ever reached in a loop.
Recommended fix
Once #856-F4 gives a concretely-typed array local (List<bool> / List<double> or bool[]/double[]):
- emit direct
get_Item / set_Item for monomorphic typed arrays, skipping the isinst ladder and the box/unbox;
- keep the ladder only as the fallback for genuinely
object-typed / polymorphic arrays.
Investigate
- Where the index get/set ladder is emitted (
RuntimeEmitter.Objects.Index.cs, ILEmitter index-assignment sites) and how to gate a typed fast path on F4's static-type info.
- Whether
$Array vs List<object> representation can be unified for the typed case, or whether a List<double>/bool[] backing store needs interop shims for $Array consumers.
Acceptance
- Monomorphic
number[]/boolean[] index ops emit a direct typed accessor, no isinst ladder, no per-element box.
- No regression in
dotnet test, Test262, TS conformance.
Scope / priority
High value, medium risk. Sequence after F4.
Part of #856 (perf epic). Depends on #856-F4 (typed locals). Drives the count-primes (28×) and array-methods (23×) gaps.
Summary
In compiled mode, every array element get/set emits a multi-way
isinsttype-dispatch ladder inline at the call site, plus index-boxing and element box/unbox — even when the array's element type is statically known (boolean[],number[]). The element store is backed byList<object>, so primitives are boxed.Evidence (emitted IL)
isPrime[j] = falseexpands inline to:This ladder is duplicated at every element site.
countPrimescompiles to 1196 bytes of IL for a sieve. Reads mirror it (isinst List<bool>→get_Item→box Boolean→IsTruthy).Bonus O(n) trap: the
push-normalize path'sIListfallback (countPrimes IL_0086, arrayMethods IL_0074) copies the entire list element-by-element into a newList<object>. Harmless when the array is alreadyList<object>(it short-circuits), but a latent O(n)-per-call hazard if that branch is ever reached in a loop.Recommended fix
Once #856-F4 gives a concretely-typed array local (
List<bool>/List<double>orbool[]/double[]):get_Item/set_Itemfor monomorphic typed arrays, skipping theisinstladder and the box/unbox;object-typed / polymorphic arrays.Investigate
RuntimeEmitter.Objects.Index.cs,ILEmitterindex-assignment sites) and how to gate a typed fast path on F4's static-type info.$ArrayvsList<object>representation can be unified for the typed case, or whether aList<double>/bool[]backing store needs interop shims for$Arrayconsumers.Acceptance
number[]/boolean[]index ops emit a direct typed accessor, noisinstladder, no per-element box.dotnet test, Test262, TS conformance.Scope / priority
High value, medium risk. Sequence after F4.