java-topology/defects/v8/unit/V8RegisterAllocatorTest.java
russell@unturf.com db29a08762 undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections.
Squash of 94 local commits onto remote master.
2026-03-26 19:48:18 -04:00

247 lines
9.9 KiB
Java

package unit;
import java.util.ArrayList;
import java.util.HashSet;
/**
* V8RegisterAllocatorTest
*
* Models the CWE-407 defect in ConstraintBuilder::MeetConstraintsBefore():
*
* Defective: ZoneVector<TopLevelLiveRange*> used for deduplication via std::find,
* producing O(k) membership test → O(k^2) total per instruction.
*
* Fixed: ZoneUnorderedSet<TopLevelLiveRange*> with .count(), O(1) membership
* test → O(k) total per instruction.
*
* Each "range pointer" is modelled as a Long ID. Comparison counts are instrumented
* explicitly — not wall-clock timing — to isolate the algorithmic difference.
*/
public class V8RegisterAllocatorTest {
// -----------------------------------------------------------------------
// Instrumented defective implementation: ArrayList + linear scan
// -----------------------------------------------------------------------
static long defectiveDedup(long[] inputRangeIds) {
ArrayList<Long> spilledConsts = null;
long comparisons = 0;
for (long rangeId : inputRangeIds) {
boolean alreadySpilled = false;
if (spilledConsts == null) {
spilledConsts = new ArrayList<>();
} else {
// O(k) linear scan — the defect
for (Long existing : spilledConsts) {
comparisons++;
if (existing.equals(rangeId)) {
alreadySpilled = true;
break;
}
}
}
if (!alreadySpilled) {
spilledConsts.add(rangeId);
}
}
return comparisons;
}
// -----------------------------------------------------------------------
// Instrumented fixed implementation: HashSet + O(1) contains
// -----------------------------------------------------------------------
static long fixedDedup(long[] inputRangeIds) {
HashSet<Long> spilledConsts = null;
long lookups = 0;
for (long rangeId : inputRangeIds) {
boolean alreadySpilled = false;
if (spilledConsts == null) {
spilledConsts = new HashSet<>();
} else {
lookups++; // one O(1) hash lookup per non-first input
alreadySpilled = spilledConsts.contains(rangeId);
}
if (!alreadySpilled) {
spilledConsts.add(rangeId);
}
}
return lookups;
}
// -----------------------------------------------------------------------
// Helper: build an input array where all k inputs map to the same k/2
// distinct range IDs, maximising the average scan length in the defect.
// -----------------------------------------------------------------------
static long[] makeInputs(int k) {
long[] ids = new long[k];
int distinct = Math.max(1, k / 2);
for (int i = 0; i < k; i++) {
ids[i] = i % distinct;
}
return ids;
}
// -----------------------------------------------------------------------
// Test 1 — Single instruction, k=50 constant-spill inputs: defect > fixed
// -----------------------------------------------------------------------
static void test1_singleInstructionRatio() {
int k = 50;
long[] inputs = makeInputs(k);
long defectOps = defectiveDedup(inputs);
long fixedOps = fixedDedup(inputs);
System.out.printf("test1: k=%d defect_comparisons=%d fixed_lookups=%d%n",
k, defectOps, fixedOps);
assert defectOps > fixedOps
: "defect must do more work than fix at k=" + k;
assert defectOps >= (k / 2) * ((k / 2) - 1) / 2
: "defect comparison count must be at least triangular for k/2 distinct ranges";
}
// -----------------------------------------------------------------------
// Test 2 — Ratio > 10x at k=50 across 100 instructions
// -----------------------------------------------------------------------
static void test2_ratioExceedsTenX() {
int k = 50;
int instructions = 100;
long[] inputs = makeInputs(k);
long totalDefect = 0;
long totalFixed = 0;
for (int i = 0; i < instructions; i++) {
totalDefect += defectiveDedup(inputs);
totalFixed += fixedDedup(inputs);
}
double ratio = (double) totalDefect / Math.max(1, totalFixed);
System.out.printf("test2: instructions=%d total_defect=%d total_fixed=%d ratio=%.1fx%n",
instructions, totalDefect, totalFixed, ratio);
assert ratio > 10.0
: "expected ratio > 10x, got " + ratio;
}
// -----------------------------------------------------------------------
// Test 3 — All inputs are unique (worst case: every input is a cache miss)
// defect is still O(k^2); fixed is O(k)
// -----------------------------------------------------------------------
static void test3_allUniqueInputs() {
int k = 60;
long[] inputs = new long[k];
for (int i = 0; i < k; i++) inputs[i] = i; // all distinct
long defectOps = defectiveDedup(inputs);
long fixedOps = fixedDedup(inputs);
// All inputs are unique → no hit ever found → no dedup gains.
// Defect: input 0 → list null, no scan (0).
// input 1 → list.size()=1, scans 1 item (full miss).
// input i → list.size()=i, scans i items.
// Total: 0 + 1 + 2 + ... + (k-1) = k*(k-1)/2
// Fixed: k-1 lookups (first input builds null→new, no lookup counted; inputs 1..k-1 each +1).
long expectedDefect = (long) k * (k - 1) / 2;
double ratio = (double) defectOps / Math.max(1, fixedOps);
System.out.printf("test3: k=%d unique defect=%d (expect=%d) fixed=%d ratio=%.1fx%n",
k, defectOps, expectedDefect, fixedOps, ratio);
assert defectOps == expectedDefect
: "defect comparisons=" + defectOps + " expected=" + expectedDefect;
assert ratio > 10.0
: "expected ratio > 10x for all-unique, got " + ratio;
}
// -----------------------------------------------------------------------
// Test 4 — All inputs map to the same range ID (degenerate: only one
// unique entry ever appended; every subsequent input hits on
// the first comparison)
// -----------------------------------------------------------------------
static void test4_allSameRangeId() {
int k = 100;
long[] inputs = new long[k];
for (int i = 0; i < k; i++) inputs[i] = 42L; // all the same
long defectOps = defectiveDedup(inputs);
long fixedOps = fixedDedup(inputs);
// Defect: first input → list is empty, no scan.
// Inputs 2..k each scan a list of length 1 → 1 comparison each = k-1.
// Fixed: each non-first input → 1 hash lookup = k-1 lookups.
// Counts are equal in this degenerate case (list always length 1), but
// the defect comparison is still pointer-equality vs hash — no asymptote yet.
System.out.printf("test4: k=%d same-id defect=%d fixed=%d%n",
k, defectOps, fixedOps);
// At minimum, defect ≥ fixed (same list length of 1 throughout)
assert defectOps >= fixedOps
: "defect should not be cheaper than fix in any case";
// Both should be exactly k-1
assert defectOps == k - 1
: "expected k-1=" + (k-1) + " defect comparisons, got " + defectOps;
}
// -----------------------------------------------------------------------
// Test 5 — Scaling: doubling k roughly quadruples defect ops, doubles fixed
// -----------------------------------------------------------------------
static void test5_quadraticVsLinearScaling() {
int k1 = 40;
int k2 = 80; // double k
long d1 = defectiveDedup(makeInputs(k1));
long d2 = defectiveDedup(makeInputs(k2));
long f1 = fixedDedup(makeInputs(k1));
long f2 = fixedDedup(makeInputs(k2));
double defectGrowth = (double) d2 / Math.max(1, d1);
double fixedGrowth = (double) f2 / Math.max(1, f1);
System.out.printf("test5: defect growth on 2x k: %.2fx fixed growth: %.2fx%n",
defectGrowth, fixedGrowth);
// Defect should grow super-linearly (>2x when k doubles for quadratic algo)
assert defectGrowth > 2.0
: "defect should grow super-linearly, got " + defectGrowth;
// Fixed should grow at most linearly (≤2.5x for 2x k, allowing hash overhead)
assert fixedGrowth <= 2.5
: "fixed should grow at most linearly, got " + fixedGrowth;
// Defect should grow meaningfully faster than fixed
assert defectGrowth > fixedGrowth
: "defect growth should exceed fixed growth";
}
// -----------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------
public static void main(String[] args) {
System.out.println("=== V8RegisterAllocatorTest ===");
System.out.println("Modelling CWE-407: MeetConstraintsBefore spilled_consts deduplication");
System.out.println();
test1_singleInstructionRatio();
System.out.println(" PASS test1_singleInstructionRatio");
test2_ratioExceedsTenX();
System.out.println(" PASS test2_ratioExceedsTenX");
test3_allUniqueInputs();
System.out.println(" PASS test3_allUniqueInputs");
test4_allSameRangeId();
System.out.println(" PASS test4_allSameRangeId");
test5_quadraticVsLinearScaling();
System.out.println(" PASS test5_quadraticVsLinearScaling");
System.out.println();
System.out.println("All 5 tests PASSED.");
}
}