wave16: dart-0001/2/3 + octave-0002 + php-0003/4 + cassandra-0005 + erlang-0003 + chef-0001 — 542/240

This commit is contained in:
russell@unturf.com 2026-03-27 19:36:35 -04:00
parent 31850d5ef6
commit d816d3c74c
18 changed files with 1902 additions and 6 deletions

View file

@ -0,0 +1,83 @@
# dart-0001: forEachOrderedParameterByFunctionNode namedParameters List.contains() — O(N²)
## Severity
MEDIUM
## Location
`pkg/compiler/lib/src/js_model/element_map.dart`
Lines 632640 (`forEachOrderedParameterByFunctionNode`)
## Description
`forEachOrderedParameterByFunctionNode` iterates over every named parameter
declaration in an IR function node and, for each one, calls
`parameterStructure.namedParameters.contains(variable.name)` to determine
whether the parameter should be marked as elided.
`ParameterStructure.namedParameters` is declared as `List<String>` (see
`pkg/compiler/lib/src/elements/entities.dart:259`). `List.contains()` is an
O(N) linear scan. The outer loop also runs N times (once per named parameter),
yielding **O(N²)** total equality comparisons per function.
This function is called at four sites in the SSA builder
(`pkg/compiler/lib/src/ssa/builder.dart:661,673,680,690,2278`) as part of the
Dart2JS compilation pipeline — once per function during code generation. For
programs with heavily-parameterised functions (e.g. large generated code,
Flutter widget constructors) this compounds across all function codegen passes.
## Defective Code
```dart
// pkg/compiler/lib/src/js_model/element_map.dart:626640
List<ir.VariableDeclaration> namedParameters = node.namedParameters.toList();
if (useNativeOrdering) {
namedParameters.sort(nativeOrdering);
} else {
namedParameters.sort(namedOrdering);
}
for (ir.VariableDeclaration variable in namedParameters) {
f(
variable,
isOptional: true,
isElided: !parameterStructure.namedParameters.contains(variable.name), // O(N) per call
);
}
```
## Root Cause
`parameterStructure.namedParameters` is `List<String>`. Each `.contains()` call
performs a full sequential scan of the list. Because this is called inside the
`for (ir.VariableDeclaration variable in namedParameters)` loop, the total cost
is O(N²) in the number of named parameters.
## Fix
Convert `parameterStructure.namedParameters` to a `Set<String>` once before
the loop. `Set.contains()` is O(1).
```dart
// FIXED
final Set<String> elidedNames = parameterStructure.namedParameters.toSet();
for (ir.VariableDeclaration variable in namedParameters) {
f(
variable,
isOptional: true,
isElided: !elidedNames.contains(variable.name), // O(1)
);
}
```
No other callers are affected because `parameterStructure.namedParameters` is
only read (not mutated) inside this function.
## Related Defects
- dart-0002: same `namedParameters.contains` pattern in `ssa/builder.dart:2156`
- dart-0003: same pattern in `ssa/builder.dart:5007`
## Complexity
| | Before | After |
|---|--------|-------|
| Named params per function | O(N²) equality scans | O(N) |
| Full program (F functions, N params avg) | O(F × N²) | O(F × N) |
## Observed Speedup
At N=500 named parameters: ~250,000 list equality scans → ~0.
Measured ratio: ≥125x at N=500 (see unit test).

View file

@ -0,0 +1,58 @@
# dart-0002: SSA builder namedParameters.contains() in .where() filter — O(N²)
## Severity
MEDIUM
## Location
`pkg/compiler/lib/src/ssa/builder.dart`
Line 2156 (function `_buildNativeInvoke` or similar native method handler)
## Description
In the SSA builder's native method handling, a `.where()` filter over
`functionNode.namedParameters` calls
`function.parameterStructure.namedParameters.contains(p.name)` to decide which
parameters to retain. The predicate runs once per item in the outer list, and
each call to `.contains()` scans the `List<String>` linearly. The result is
O(N²) where N is the number of named parameters.
## Defective Code
```dart
// pkg/compiler/lib/src/ssa/builder.dart:21512163
if (functionNode.namedParameters.isNotEmpty) {
List<ir.VariableDeclaration> namedParameters = functionNode
.namedParameters
// Filter elided parameters.
.where(
(p) => function.parameterStructure.namedParameters.contains(p.name), // O(N) per element
)
.toList();
namedParameters.sort(nativeOrdering);
namedParameters.forEach(handleParameter);
}
```
## Fix
```dart
// FIXED
if (functionNode.namedParameters.isNotEmpty) {
final Set<String> liveNames =
function.parameterStructure.namedParameters.toSet(); // O(N) once
List<ir.VariableDeclaration> namedParameters = functionNode
.namedParameters
.where((p) => liveNames.contains(p.name)) // O(1) per element
.toList();
namedParameters.sort(nativeOrdering);
namedParameters.forEach(handleParameter);
}
```
## Complexity
| | Before | After |
|---|--------|-------|
| Per function | O(N²) | O(N) |
## Related
- dart-0001: same root cause in `element_map.dart`
- dart-0003: same pattern at `builder.dart:5007`

View file

@ -0,0 +1,56 @@
# dart-0003: SSA builder namedParameters.contains() in argument ordering — O(N²)
## Severity
MEDIUM
## Location
`pkg/compiler/lib/src/ssa/builder.dart`
Line 5007 (argument ordering logic in call-site code generation)
## Description
During call-site code generation the SSA builder sorts named arguments into
parameter-position order. It filters the target function's declared named
parameters using:
```dart
target.namedParameters
.where((p) => parameterStructure.namedParameters.contains(p.name))
```
`parameterStructure.namedParameters` is `List<String>`. The `.where()` predicate
is called once per item in `target.namedParameters`, and each predicate call does
a full O(N) linear scan of the `List<String>`. Total cost: O(N²).
## Defective Code
```dart
// pkg/compiler/lib/src/ssa/builder.dart:50005011
List<ir.VariableDeclaration> namedParameters =
target.namedParameters
// Filter elided parameters.
.where((p) => parameterStructure.namedParameters.contains(p.name)) // O(N) per call
.toList()
..sort(namedOrdering);
```
## Fix
```dart
// FIXED
final Set<String> liveNames =
parameterStructure.namedParameters.toSet(); // O(N) once
List<ir.VariableDeclaration> namedParameters =
target.namedParameters
.where((p) => liveNames.contains(p.name)) // O(1) per call
.toList()
..sort(namedOrdering);
```
## Complexity
| | Before | After |
|---|--------|-------|
| Per call site | O(N²) | O(N) |
## Related
- dart-0001: same root cause in `element_map.dart`
- dart-0002: same pattern at `builder.dart:2156`