From d915e39511c29e7d9a52a01e9bddc9c54edc7efb Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 7 Mar 2026 18:05:18 +0000 Subject: [PATCH] implements PR-O1.6 --- .../stages/BackendSafetyGateSUTest.java | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/workspaces/stages/BackendSafetyGateSUTest.java diff --git a/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/workspaces/stages/BackendSafetyGateSUTest.java b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/workspaces/stages/BackendSafetyGateSUTest.java new file mode 100644 index 00000000..95be4d3a --- /dev/null +++ b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/workspaces/stages/BackendSafetyGateSUTest.java @@ -0,0 +1,168 @@ +package p.studio.compiler.workspaces.stages; + +import org.junit.jupiter.api.Test; +import p.studio.compiler.backend.bytecode.BytecodeEmitter; +import p.studio.compiler.backend.irvm.IRVMFunction; +import p.studio.compiler.backend.irvm.IRVMInstruction; +import p.studio.compiler.backend.irvm.IRVMModule; +import p.studio.compiler.backend.irvm.IRVMOp; +import p.studio.compiler.backend.irvm.IRVMProgram; +import p.studio.compiler.messages.BuilderPipelineConfig; +import p.studio.compiler.models.BuilderPipelineContext; +import p.studio.compiler.models.IRBackend; +import p.studio.compiler.models.IRBackendExecutableFunction; +import p.studio.compiler.source.Span; +import p.studio.compiler.source.identifiers.FileId; +import p.studio.utilities.logs.LogAggregator; +import p.studio.utilities.structures.ReadOnlyList; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class BackendSafetyGateSUTest { + + @Test + void lowerStageMustExposeDeterministicFailureCodeForSameInvalidInput() { + final var backend = IRBackend.builder() + .executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction( + new FileId(1), + "app", + "main", + 0, + 10, + 0, + 0, + 0, + 2, + ReadOnlyList.from( + new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.CALL_FUNC, + "app", + "missing", + null, + null, + 0, + 0, + Span.none()), + new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.RET, + "", + "", + null, + null, + Span.none())), + Span.none()))) + .build(); + + final var issueA = runLower(backend).asCollection().iterator().next(); + final var issueB = runLower(backend).asCollection().iterator().next(); + + assertEquals("LOWER_IRVM_MISSING_CALLEE", issueA.getCode()); + assertEquals(issueA.getCode(), issueB.getCode()); + assertEquals(issueA.getPhase(), issueB.getPhase()); + } + + @Test + void optimizeStageMustBeDeterministicForSameInputProgram() { + final var program = new IRVMProgram(new IRVMModule( + "core-v1", + ReadOnlyList.from(new IRVMFunction( + "main", + 0, + 0, + 0, + 1, + ReadOnlyList.from(new IRVMInstruction(IRVMOp.HALT, null)))))); + + final var first = runOptimize(program); + final var second = runOptimize(program); + + assertTrue(!first.hasErrors()); + assertTrue(!second.hasErrors()); + assertEquals(first.size(), second.size()); + } + + @Test + void emitStageMustExposeMarshalingLinkageFailureDeterministically() { + 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 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(issueA.getCode(), issueB.getCode()); + assertEquals(issueA.getPhase(), issueB.getPhase()); + } + + @Test + void fullPipelineMustProduceDeterministicBytecodeForSameInput() { + final var backend = IRBackend.builder() + .executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction( + new FileId(1), + "app", + "main", + 0, + 10, + 0, + 0, + 0, + 1, + ReadOnlyList.from(new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.RET, + "", + "", + null, + null, + Span.none())), + Span.none()))) + .build(); + + final var first = emitBytes(backend); + final var second = emitBytes(backend); + + assertArrayEquals(first, second); + } + + private static p.studio.compiler.messages.BuildingIssueSink runLower(final IRBackend backend) { + final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, ".")); + ctx.irBackend = backend; + return new LowerToIRVMPipelineStage().run(ctx, LogAggregator.empty()); + } + + private static p.studio.compiler.messages.BuildingIssueSink runOptimize(final IRVMProgram program) { + final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, ".")); + ctx.irvm = program; + return new OptimizeIRVMPipelineStage().run(ctx, LogAggregator.empty()); + } + + private static p.studio.compiler.messages.BuildingIssueSink runEmit(final IRVMProgram program) { + final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, ".")); + ctx.optimizedIrvm = program; + return new EmitBytecodePipelineStage().run(ctx, LogAggregator.empty()); + } + + private static byte[] emitBytes(final IRBackend backend) { + final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, ".")); + ctx.irBackend = backend; + + final var lowerIssues = new LowerToIRVMPipelineStage().run(ctx, LogAggregator.empty()); + final var optimizeIssues = new OptimizeIRVMPipelineStage().run(ctx, LogAggregator.empty()); + final var emitIssues = new EmitBytecodePipelineStage().run(ctx, LogAggregator.empty()); + + assertTrue(!lowerIssues.hasErrors()); + assertTrue(!optimizeIssues.hasErrors()); + assertTrue(!emitIssues.hasErrors()); + return ctx.bytecodeBytes; + } +}