implements PR-O1.6

This commit is contained in:
bQUARKz 2026-03-07 18:05:18 +00:00
parent b5622bd9df
commit d915e39511
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8

View File

@ -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;
}
}