Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions compliance_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Spec compliance report

| Compiler | Status | Issues |
|----------|--------|--------|
| l1a | ✅ PASS | None |
| l1b | ✅ PASS | None |
| l2 | ✅ PASS | None |

---

## Details

### l1a Implementation
- **Status:** ✅ PASS
- **Files:** `core/src/core/org/jnode/vm/x86/compiler/l1a/X86BytecodeVisitor.java:2292-2341`
- **Issues:** None

**Analysis:**
- **Stack effect**: Correctly pops two `IntItem` values from virtual stack (`vstack.popInt()` ×2) — matches JVM spec "..., value1, value2 → ..."
- **Signed comparison**: Uses `X86Constants.JGE` (0x8D, "Jump if Greater or Equal" signed) — matches JVM spec "ge succeeds if and only if value1 ≥ value2 (signed)"
- **Branch target**: Parser computes `address + gets2()` where `gets2()` reads signed 16-bit offset — matches JVM spec "(branchbyte1 << 8) | branchbyte2" as signed 16-bit
- **Basic block barrier**: Flushes virtual stack via `vstack.push(eContext)` before emitting jump — correct for control-flow boundaries
- **Operand handling**: `prepareForOperation` ensures `value1` (v1) is in a register; `value2` (v2) can be register, local, or constant — correct for x86 CMP dest, src
- **Commutativity handling**: Only swaps for JE/JNE (equality); correctly does NOT swap for JGE/JG/JL/JLE — x86 CMP is dest−src, so operand order matters for signed relational ops
- **Yield point**: Not emitted for forward branches; backward branches handled at caller level — acceptable

### l1b Implementation
- **Status:** ✅ PASS
- **Files:** `core/src/core/org/jnode/vm/x86/compiler/l1b/X86BytecodeVisitor.java:2809-2884`
- **Issues:** None

**Analysis:**
- Identical logic to l1a for `visit_if_icmp` helper and `visit_if_icmpge` dispatch
- Adds bytecode counters (`countBytecode`, `countConstOps`) for metrics — no functional impact
- Same constant-folding TODO comments as l1a — not a spec violation, optimization opportunity only

### l2 Implementation
- **Status:** ✅ PASS
- **Files:**
- `core/src/core/org/jnode/vm/x86/compiler/l2/GenericX86CodeGenerator.java:3787-3824` (codegen)
- `core/src/core/org/jnode/vm/compiler/ir/quad/BranchCondition.java:30-31` (IR enum)
- `core/src/core/org/jnode/vm/compiler/ir/IRGenerator.java:917` (IR generation)
- `core/src/core/org/jnode/vm/bytecode/BasicBlockFinder.java:218-223` (stack simulation)
- **Issues:** None

**Analysis:**
- **IR representation**: `BranchCondition.IF_ICMPGE(">=", true)` — `binary=true` correctly indicates two stack operands
- **IR generation**: `IRGenerator.visitBranchCondition` creates `ConditionalBranchQuad` with two stack slots (s1, s2) of type `Operand.INT` — matches stack effect
- **Basic block finder**: Pops two `JvmType.INT` from type stack, calls `addBranch(address, true)` and `condYieldPoint` — correct control-flow construction
- **Code generation**: `generateJumpForBinaryCondition` switches on `IF_ICMPGE` → emits `os.writeJCC(target, X86Constants.JGE)` — correct signed ≥
- **Support checker**: `L2ByteCodeSupportChecker` does NOT override `visit_if_icmpge` — inherits empty impl from `BytecodeVisitorSupport`, meaning instruction is **supported** (unsupported ops explicitly throw)
- **Branch offset**: Uses same parser (`BytecodeParser.gets2()`) for signed 16-bit target — correct

---

## JVM Spec References (Java SE 6)

- **Opcode**: `if_icmpge` = 162 (0xA2)
- **Operand Stack**: `..., value1, value2 → ...` (both `int`, both popped)
- **Comparison**: Signed integer comparison; branch taken iff `value1 ≥ value2`
- **Branch Offset**: Signed 16-bit constructed from `branchbyte1`, `branchbyte2`; target = `address + offset`
- **Target Constraint**: Must be an opcode within the same method

All three JNode compiler tiers implement the above faithfully. No spec violations found.
Loading