147 lines
5.1 KiB
Java
147 lines
5.1 KiB
Java
package unit;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.HashMap;
|
||
import java.util.HashSet;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* JSC-0001: BytecodeBasicBlock::computeImpl() O(B²×T) edge linking.
|
||
*
|
||
* Models the inner loop in BytecodeBasicBlock.cpp lines 181-193:
|
||
* - SlowLinker: for each branch block, scan all B blocks and call
|
||
* Vector::contains(jumpTargets) for each — O(B × T) per branch
|
||
* - FastLinker: load jump targets into HashSet first — O(B + T) per branch
|
||
*
|
||
* Compile: javac -d . *.java (from defects/jsc/unit/)
|
||
* Run: java -ea unit.JSCBytecodeBasicBlockTest
|
||
*/
|
||
public class JSCBytecodeBasicBlockTest {
|
||
|
||
// ---- slow path: Vector<Offset> linear contains --------------------------
|
||
|
||
static class SlowLinker {
|
||
static long opCount;
|
||
|
||
/**
|
||
* @param blockCount total basic blocks (B)
|
||
* @param jumpTargets list of target offsets (size T)
|
||
* @return number of (block, target) linkage operations found
|
||
*/
|
||
static int link(int blockCount, List<Integer> jumpTargets) {
|
||
int linked = 0;
|
||
// Simulate: for (auto& otherBlock : basicBlocks)
|
||
for (int blockId = 0; blockId < blockCount; blockId++) {
|
||
// Simulate: bytecodeOffsetsJumpedTo.contains(otherBlock.leaderOffset())
|
||
for (Integer target : jumpTargets) {
|
||
opCount++;
|
||
if (target == blockId) {
|
||
linked++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return linked;
|
||
}
|
||
}
|
||
|
||
// ---- fast path: HashSet<Offset> O(1) lookup -----------------------------
|
||
|
||
static class FastLinker {
|
||
static long opCount;
|
||
|
||
static int link(int blockCount, List<Integer> jumpTargets) {
|
||
// Build HashSet once: O(T)
|
||
HashSet<Integer> targetSet = new HashSet<>(jumpTargets);
|
||
opCount += jumpTargets.size(); // insertions
|
||
|
||
int linked = 0;
|
||
// Simulate: for (auto& otherBlock : basicBlocks)
|
||
for (int blockId = 0; blockId < blockCount; blockId++) {
|
||
opCount++; // one hash lookup
|
||
if (targetSet.contains(blockId)) {
|
||
linked++;
|
||
}
|
||
}
|
||
return linked;
|
||
}
|
||
}
|
||
|
||
// ---- helpers ------------------------------------------------------------
|
||
|
||
static List<Integer> makeTargets(int blockCount, int T) {
|
||
// T evenly-spaced target block offsets
|
||
List<Integer> targets = new ArrayList<>(T);
|
||
int step = Math.max(1, blockCount / T);
|
||
for (int i = 0; i < T && i * step < blockCount; i++)
|
||
targets.add(i * step);
|
||
return targets;
|
||
}
|
||
|
||
// ---- tests --------------------------------------------------------------
|
||
|
||
static int passed = 0;
|
||
static int total = 0;
|
||
|
||
static void check(String name, boolean cond) {
|
||
total++;
|
||
if (cond) {
|
||
passed++;
|
||
} else {
|
||
System.out.println("FAIL: " + name);
|
||
}
|
||
}
|
||
|
||
public static void main(String[] args) {
|
||
// correctness: both find same number of links
|
||
{
|
||
int B = 20, T = 4;
|
||
List<Integer> targets = makeTargets(B, T);
|
||
SlowLinker.opCount = 0;
|
||
FastLinker.opCount = 0;
|
||
int slowLinks = SlowLinker.link(B, targets);
|
||
int fastLinks = FastLinker.link(B, targets);
|
||
check("slow and fast agree on link count", slowLinks == fastLinks);
|
||
check("linked count == T", slowLinks == T);
|
||
}
|
||
|
||
// op-count scaling
|
||
int[] blockCounts = {50, 100, 200, 500};
|
||
int[] switchSizes = {10, 50, 200, 500};
|
||
|
||
System.out.println();
|
||
System.out.printf("%-8s %-8s %14s %14s %10s%n",
|
||
"B", "T", "slow_ops", "fast_ops", "ratio");
|
||
|
||
for (int B : blockCounts) {
|
||
for (int T : switchSizes) {
|
||
if (T > B) continue;
|
||
List<Integer> targets = makeTargets(B, T);
|
||
SlowLinker.opCount = 0;
|
||
FastLinker.opCount = 0;
|
||
int slowLinks = SlowLinker.link(B, targets);
|
||
int fastLinks = FastLinker.link(B, targets);
|
||
check("results agree B=" + B + " T=" + T, slowLinks == fastLinks);
|
||
|
||
long slow = SlowLinker.opCount;
|
||
long fast = FastLinker.opCount;
|
||
double ratio = (double) slow / fast;
|
||
System.out.printf("%-8d %-8d %14d %14d %10.1f%n",
|
||
B, T, slow, fast, ratio);
|
||
|
||
// slow ops ~ O(B × T), fast ops ~ O(B + T)
|
||
// ratio should grow with min(B,T)
|
||
int minBT = Math.min(B, T);
|
||
check("slow > fast for B=" + B + " T=" + T, slow > fast);
|
||
// for large T, ratio should be at least T/4
|
||
if (T >= 50) {
|
||
check("ratio >= T/4 for T=" + T, ratio >= (double) T / 4);
|
||
}
|
||
}
|
||
}
|
||
|
||
System.out.println();
|
||
System.out.printf("%d/%d PASS%n", passed, total);
|
||
if (passed != total) System.exit(1);
|
||
}
|
||
}
|