implements PR-09.3: enforce qualified entrypoint and moduleId-only ordering in LowerToIRVM
This commit is contained in:
parent
5c69a02973
commit
8876a8fa35
@ -297,6 +297,11 @@ public class LowerToIRVMService {
|
||||
"frontend IRBackend entrypoint declaration is missing");
|
||||
}
|
||||
final var entryPointModuleId = backend.getEntryPointModuleId();
|
||||
if (entryPointModuleId == null || entryPointModuleId.isNone()) {
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_DECLARATION_MISSING,
|
||||
"frontend IRBackend qualified entrypoint declaration is missing entryPointModuleId");
|
||||
}
|
||||
final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList());
|
||||
sorted.sort((left, right) -> {
|
||||
final var leftModuleKey = moduleSortKey(backend, left.moduleId());
|
||||
@ -315,44 +320,25 @@ public class LowerToIRVMService {
|
||||
}
|
||||
return Integer.compare(left.sourceStart(), right.sourceStart());
|
||||
});
|
||||
final java.util.List<IRBackendExecutableFunction> entrypoints;
|
||||
if (entryPointModuleId != null && !entryPointModuleId.isNone()) {
|
||||
final var expectedModuleIndex = entryPointModuleId.getIndex();
|
||||
entrypoints = sorted.stream()
|
||||
.filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
|
||||
.filter(candidate -> !candidate.moduleId().isNone() && candidate.moduleId().getIndex() == expectedModuleIndex)
|
||||
.toList();
|
||||
} else {
|
||||
entrypoints = sorted.stream()
|
||||
.filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
|
||||
.toList();
|
||||
}
|
||||
final var expectedModuleIndex = entryPointModuleId.getIndex();
|
||||
final var entrypoints = sorted.stream()
|
||||
.filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
|
||||
.filter(candidate -> !candidate.moduleId().isNone() && candidate.moduleId().getIndex() == expectedModuleIndex)
|
||||
.toList();
|
||||
if (entrypoints.isEmpty()) {
|
||||
if (entryPointModuleId != null && !entryPointModuleId.isNone()) {
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_MISSING,
|
||||
"missing qualified entrypoint callable '%s' for moduleId=%d".formatted(
|
||||
entryPointCallableName,
|
||||
entryPointModuleId.getIndex()));
|
||||
}
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_MISSING,
|
||||
"missing entrypoint callable '%s'".formatted(entryPointCallableName));
|
||||
"missing qualified entrypoint callable '%s' for moduleId=%d".formatted(
|
||||
entryPointCallableName,
|
||||
entryPointModuleId.getIndex()));
|
||||
}
|
||||
if (entrypoints.size() > 1) {
|
||||
if (entryPointModuleId != null && !entryPointModuleId.isNone()) {
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS,
|
||||
"ambiguous qualified entrypoint: found %d callables named '%s' in moduleId=%d".formatted(
|
||||
entrypoints.size(),
|
||||
entryPointCallableName,
|
||||
entryPointModuleId.getIndex()));
|
||||
}
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS,
|
||||
"ambiguous entrypoint: found %d callables named '%s'".formatted(
|
||||
"ambiguous qualified entrypoint: found %d callables named '%s' in moduleId=%d".formatted(
|
||||
entrypoints.size(),
|
||||
entryPointCallableName));
|
||||
entryPointCallableName,
|
||||
entryPointModuleId.getIndex()));
|
||||
}
|
||||
final var entrypoint = entrypoints.getFirst();
|
||||
final var ordered = new ArrayList<IRBackendExecutableFunction>(sorted.size());
|
||||
|
||||
@ -43,8 +43,10 @@ class GoldenArtifactsTest {
|
||||
|
||||
private IRBackend fixtureBackend() {
|
||||
return IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(0),
|
||||
0,
|
||||
|
||||
@ -21,6 +21,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustAssignEntrypointIdZeroAndSortRemainingDeterministically() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("aux", "app", 11, ReadOnlyList.from(
|
||||
callFunc("app", "main", 10),
|
||||
@ -42,6 +43,7 @@ class LowerToIRVMServiceTest {
|
||||
void lowerMustUseFrontendDeclaredEntrypointCallable() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("frame")
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("aux", "app", 11, ReadOnlyList.from(
|
||||
callFunc("app", "frame", 10),
|
||||
@ -60,6 +62,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustMapHostAndIntrinsicCallsites() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
callHost("gfx", "draw_pixel", 1, 0, 0),
|
||||
@ -83,6 +86,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectUnterminatedFunction() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
callFunc("app", "main", 10)))))
|
||||
@ -95,6 +99,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectMissingCallee() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
callFunc("app", "missing", 77),
|
||||
@ -108,6 +113,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectUnknownCanonicalIntrinsicIdentity() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
callIntrinsic("core.color.pack", 1, 0),
|
||||
@ -123,6 +129,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectCallArgSlotMismatch() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("callee", "app", 20, ReadOnlyList.from(ret())),
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
@ -137,6 +144,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustResolveJumpTargetsFromLabels() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
label("entry"),
|
||||
@ -156,6 +164,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectMissingJumpTargetLabel() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(
|
||||
jmp("missing"),
|
||||
@ -169,6 +178,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectWhenEntrypointIsMissing() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("helper", "app", 10, ReadOnlyList.from(ret()))))
|
||||
.build();
|
||||
@ -192,6 +202,7 @@ class LowerToIRVMServiceTest {
|
||||
@Test
|
||||
void lowerMustRejectWhenEntrypointIsAmbiguous() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", "app", 10, ReadOnlyList.from(ret())),
|
||||
fn("main", "sdk", 11, ReadOnlyList.from(ret()))))
|
||||
@ -205,6 +216,7 @@ class LowerToIRVMServiceTest {
|
||||
void lowerMustUseModulePoolCanonicalIdentityForNonEntrypointOrdering() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("frame")
|
||||
.entryPointModuleId(new ModuleId(1))
|
||||
.modulePool(ReadOnlyList.from(
|
||||
new ModuleReference("app", ReadOnlyList.from("alpha")),
|
||||
new ModuleReference("app", ReadOnlyList.from("zeta"))))
|
||||
@ -264,6 +276,7 @@ class LowerToIRVMServiceTest {
|
||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||
return new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new ModuleId(0),
|
||||
name,
|
||||
new CallableId(callableId),
|
||||
0,
|
||||
|
||||
@ -28,6 +28,7 @@ class OptimizeIRVMEquivalenceHarnessTest {
|
||||
@Test
|
||||
void optimizeOnOffMustPreserveObservableTraceForLoweredHostIntrinsicFixture() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("main", 1, ReadOnlyList.from(
|
||||
callHost("gfx", "draw_pixel", 1, 0, 0),
|
||||
@ -322,6 +323,7 @@ class OptimizeIRVMEquivalenceHarnessTest {
|
||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||
return new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
name,
|
||||
new CallableId(callableId),
|
||||
0,
|
||||
|
||||
@ -178,6 +178,7 @@ class BackendGateIIntegrationTest {
|
||||
final IRBackendExecutableFunction function,
|
||||
final ReadOnlyList<IntrinsicReference> intrinsicPool) {
|
||||
return IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(function))
|
||||
.intrinsicPool(intrinsicPool)
|
||||
.build();
|
||||
@ -188,6 +189,7 @@ class BackendGateIIntegrationTest {
|
||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||
return new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
name,
|
||||
new CallableId(1),
|
||||
0,
|
||||
|
||||
@ -26,8 +26,10 @@ class BackendSafetyGateSUTest {
|
||||
@Test
|
||||
void lowerStageMustExposeDeterministicFailureCodeForSameInvalidInput() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
0,
|
||||
@ -109,8 +111,10 @@ class BackendSafetyGateSUTest {
|
||||
@Test
|
||||
void fullPipelineMustProduceDeterministicBytecodeForSameInput() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
0,
|
||||
|
||||
@ -36,8 +36,10 @@ class LowerToIRVMPipelineStageTest {
|
||||
void runMustLowerExecutableFunctionsToIrvm() {
|
||||
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
|
||||
ctx.irBackend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
0,
|
||||
@ -67,8 +69,10 @@ class LowerToIRVMPipelineStageTest {
|
||||
void runMustPropagateConfiguredVmProfileToLowering() {
|
||||
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, ".", "experimental-v1"));
|
||||
ctx.irBackend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
0,
|
||||
@ -98,8 +102,10 @@ class LowerToIRVMPipelineStageTest {
|
||||
final var callSpan = new Span(new FileId(9), 12, 24);
|
||||
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
|
||||
ctx.irBackend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||
new FileId(9),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
10,
|
||||
@ -140,9 +146,11 @@ class LowerToIRVMPipelineStageTest {
|
||||
void runMustRejectCallWhenStackDoesNotProvideDeclaredArgs() {
|
||||
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
|
||||
ctx.irBackend = IRBackend.builder()
|
||||
.entryPointModuleId(new p.studio.compiler.source.identifiers.ModuleId(0))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"callee",
|
||||
new CallableId(2),
|
||||
0,
|
||||
@ -160,6 +168,7 @@ class LowerToIRVMPipelineStageTest {
|
||||
Span.none()),
|
||||
new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new p.studio.compiler.source.identifiers.ModuleId(0),
|
||||
"main",
|
||||
new CallableId(1),
|
||||
0,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user