implements PR-05.4

This commit is contained in:
bQUARKz 2026-03-09 06:59:58 +00:00
parent ee25b867a7
commit 6a7cd6a40a
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
3 changed files with 51 additions and 8 deletions

View File

@ -36,9 +36,7 @@ public record IRVMProgram(
if (emissionPlan.functions().isEmpty()) {
return deriveEmissionPlan(module);
}
if (containsRawSyscall(emissionPlan)) {
return emissionPlan;
}
validateCanonicalPlan(emissionPlan);
validateCoherence(module, emissionPlan);
return emissionPlan;
}
@ -134,6 +132,19 @@ public record IRVMProgram(
return false;
}
private void validateCanonicalPlan(final BytecodeEmitter.EmissionPlan plan) {
for (final var function : plan.functions()) {
for (final var operation : function.operations()) {
if (operation.kind() == BytecodeEmitter.OperationKind.RAW_SYSCALL) {
throw new IllegalArgumentException("raw syscall operation is forbidden in canonical IRVM emission plan");
}
if (operation.kind() == BytecodeEmitter.OperationKind.HOSTCALL && operation.syscallDecl() == null) {
throw new IllegalArgumentException("hostcall operation requires syscall declaration metadata");
}
}
}
}
private BytecodeEmitter.Operation deriveOperation(final IRVMInstruction instruction) {
final var immediate = instruction.immediate() == null ? 0 : instruction.immediate();
return switch (instruction.op().opcode()) {
@ -143,10 +154,8 @@ public record IRVMProgram(
case 0x02 -> BytecodeEmitter.Operation.jmp(immediate, null);
case 0x04 -> BytecodeEmitter.Operation.jmpIfTrue(immediate, null);
case 0x03 -> BytecodeEmitter.Operation.jmpIfFalse(immediate, null);
case 0x71 -> BytecodeEmitter.Operation.hostcall(
new BytecodeModule.SyscallDecl("__unknown__", "__unknown__", 0, 0, 0),
null,
null);
case 0x71 -> throw new IllegalArgumentException(
"cannot derive HOSTCALL operation without canonical syscall metadata");
case 0x72 -> BytecodeEmitter.Operation.intrinsic(immediate);
default -> throw new IllegalArgumentException("cannot derive emission op for irvm opcode: " + instruction.op().opcode());
};

View File

@ -52,4 +52,38 @@ class IRVMProgramTest {
assertEquals(1, plan.functions().size());
assertEquals(BytecodeEmitter.OperationKind.HALT, plan.functions().getFirst().operations().getFirst().kind());
}
@Test
void coherentEmissionPlanMustRejectRawSyscallOperationInCanonicalPlan() {
final var plan = new BytecodeEmitter.EmissionPlan(
0,
ReadOnlyList.empty(),
ReadOnlyList.empty(),
ReadOnlyList.from(new BytecodeEmitter.FunctionPlan(
"main",
0,
0,
0,
1,
ReadOnlyList.from(BytecodeEmitter.Operation.rawSyscall(0x1001)))));
final var program = new IRVMProgram(false, plan);
assertThrows(IllegalArgumentException.class, program::coherentEmissionPlan);
}
@Test
void coherentEmissionPlanMustRejectHostcallWithoutMetadataWhenDerived() {
final var module = new IRVMModule(
"core-v1",
ReadOnlyList.from(new IRVMFunction(
"main",
0,
0,
0,
1,
ReadOnlyList.from(new IRVMInstruction(IRVMOp.HOSTCALL, 0)))));
final var program = new IRVMProgram(module, BytecodeEmitter.EmissionPlan.empty());
assertThrows(IllegalArgumentException.class, program::coherentEmissionPlan);
}
}

View File

@ -103,7 +103,7 @@ class BackendSafetyGateSUTest {
final var issueA = runEmit(new IRVMProgram(false, plan)).asCollection().iterator().next();
final var issueB = runEmit(new IRVMProgram(false, plan)).asCollection().iterator().next();
assertEquals("MARSHAL_LINKAGE_RAW_SYSCALL_IN_PRELOAD", issueA.getCode());
assertEquals("MARSHAL_VERIFY_PRECHECK_IRVM_PROGRAM_COHERENCE", issueA.getCode());
assertEquals(issueA.getCode(), issueB.getCode());
assertEquals(issueA.getPhase(), issueB.getPhase());
}