implements PR-05.4
This commit is contained in:
parent
ee25b867a7
commit
6a7cd6a40a
@ -36,9 +36,7 @@ public record IRVMProgram(
|
|||||||
if (emissionPlan.functions().isEmpty()) {
|
if (emissionPlan.functions().isEmpty()) {
|
||||||
return deriveEmissionPlan(module);
|
return deriveEmissionPlan(module);
|
||||||
}
|
}
|
||||||
if (containsRawSyscall(emissionPlan)) {
|
validateCanonicalPlan(emissionPlan);
|
||||||
return emissionPlan;
|
|
||||||
}
|
|
||||||
validateCoherence(module, emissionPlan);
|
validateCoherence(module, emissionPlan);
|
||||||
return emissionPlan;
|
return emissionPlan;
|
||||||
}
|
}
|
||||||
@ -134,6 +132,19 @@ public record IRVMProgram(
|
|||||||
return false;
|
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) {
|
private BytecodeEmitter.Operation deriveOperation(final IRVMInstruction instruction) {
|
||||||
final var immediate = instruction.immediate() == null ? 0 : instruction.immediate();
|
final var immediate = instruction.immediate() == null ? 0 : instruction.immediate();
|
||||||
return switch (instruction.op().opcode()) {
|
return switch (instruction.op().opcode()) {
|
||||||
@ -143,10 +154,8 @@ public record IRVMProgram(
|
|||||||
case 0x02 -> BytecodeEmitter.Operation.jmp(immediate, null);
|
case 0x02 -> BytecodeEmitter.Operation.jmp(immediate, null);
|
||||||
case 0x04 -> BytecodeEmitter.Operation.jmpIfTrue(immediate, null);
|
case 0x04 -> BytecodeEmitter.Operation.jmpIfTrue(immediate, null);
|
||||||
case 0x03 -> BytecodeEmitter.Operation.jmpIfFalse(immediate, null);
|
case 0x03 -> BytecodeEmitter.Operation.jmpIfFalse(immediate, null);
|
||||||
case 0x71 -> BytecodeEmitter.Operation.hostcall(
|
case 0x71 -> throw new IllegalArgumentException(
|
||||||
new BytecodeModule.SyscallDecl("__unknown__", "__unknown__", 0, 0, 0),
|
"cannot derive HOSTCALL operation without canonical syscall metadata");
|
||||||
null,
|
|
||||||
null);
|
|
||||||
case 0x72 -> BytecodeEmitter.Operation.intrinsic(immediate);
|
case 0x72 -> BytecodeEmitter.Operation.intrinsic(immediate);
|
||||||
default -> throw new IllegalArgumentException("cannot derive emission op for irvm opcode: " + instruction.op().opcode());
|
default -> throw new IllegalArgumentException("cannot derive emission op for irvm opcode: " + instruction.op().opcode());
|
||||||
};
|
};
|
||||||
|
|||||||
@ -52,4 +52,38 @@ class IRVMProgramTest {
|
|||||||
assertEquals(1, plan.functions().size());
|
assertEquals(1, plan.functions().size());
|
||||||
assertEquals(BytecodeEmitter.OperationKind.HALT, plan.functions().getFirst().operations().getFirst().kind());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class BackendSafetyGateSUTest {
|
|||||||
final var issueA = runEmit(new IRVMProgram(false, plan)).asCollection().iterator().next();
|
final var issueA = runEmit(new IRVMProgram(false, plan)).asCollection().iterator().next();
|
||||||
final var issueB = 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.getCode(), issueB.getCode());
|
||||||
assertEquals(issueA.getPhase(), issueB.getPhase());
|
assertEquals(issueA.getPhase(), issueB.getPhase());
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user