implements PR-08.3
This commit is contained in:
parent
0490f64870
commit
2a68d27eca
@ -38,6 +38,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -191,13 +192,26 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||
}
|
||||
|
||||
final var blockedModuleIds = blockedModulesByDependency(failedModuleIds, moduleDependencyGraph);
|
||||
final var entryPointCallableName = PBSDefinitions.PBS.getEntryPointCallableName();
|
||||
final var entryPointModuleCandidates = new LinkedHashSet<ModuleId>();
|
||||
for (final var compiledSource : compiledSourceFiles) {
|
||||
if (blockedModuleIds.contains(compiledSource.moduleId())) {
|
||||
continue;
|
||||
}
|
||||
irBackendAggregator.merge(compiledSource.irBackendFile());
|
||||
for (final var executable : compiledSource.irBackendFile().executableFunctions()) {
|
||||
if (!entryPointCallableName.equals(executable.callableName())) {
|
||||
continue;
|
||||
}
|
||||
if (executable.moduleId() != null && !executable.moduleId().isNone()) {
|
||||
entryPointModuleCandidates.add(executable.moduleId());
|
||||
}
|
||||
}
|
||||
}
|
||||
irBackendAggregator.entryPointCallableName(entryPointCallableName);
|
||||
if (entryPointModuleCandidates.size() == 1) {
|
||||
irBackendAggregator.entryPointModuleId(entryPointModuleCandidates.iterator().next());
|
||||
}
|
||||
irBackendAggregator.entryPointCallableName(PBSDefinitions.PBS.getEntryPointCallableName());
|
||||
|
||||
final var irBackend = irBackendAggregator.emit();
|
||||
logs.using(log).debug("PBS frontend lowered to IR BE:\n%s".formatted(irBackend));
|
||||
|
||||
@ -296,6 +296,7 @@ public class LowerToIRVMService {
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_DECLARATION_MISSING,
|
||||
"frontend IRBackend entrypoint declaration is missing");
|
||||
}
|
||||
final var entryPointModuleId = backend.getEntryPointModuleId();
|
||||
final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList());
|
||||
sorted.sort((left, right) -> {
|
||||
final var leftModuleKey = moduleSortKey(backend, left.moduleId(), left.moduleKey());
|
||||
@ -314,15 +315,39 @@ public class LowerToIRVMService {
|
||||
}
|
||||
return Integer.compare(left.sourceStart(), right.sourceStart());
|
||||
});
|
||||
final var entrypoints = sorted.stream()
|
||||
.filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
|
||||
.toList();
|
||||
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();
|
||||
}
|
||||
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));
|
||||
}
|
||||
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(
|
||||
|
||||
@ -222,6 +222,41 @@ class LowerToIRVMServiceTest {
|
||||
assertEquals("helper_in_zeta", lowered.module().functions().get(2).name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lowerMustUseQualifiedEntrypointIdentityWhenProvided() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("main")
|
||||
.entryPointModuleId(new ModuleId(1))
|
||||
.modulePool(ReadOnlyList.from(
|
||||
new ModuleReference("app", ReadOnlyList.from("alpha")),
|
||||
new ModuleReference("app", ReadOnlyList.from("beta"))))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fnWithModuleAndLocals("main", "legacy/alpha", 0, 30, 1, ReadOnlyList.from(ret())),
|
||||
fnWithModuleAndLocals("main", "legacy/beta", 1, 31, 9, ReadOnlyList.from(ret())),
|
||||
fnWithModule("helper", "legacy/alpha", 0, 32, ReadOnlyList.from(ret()))))
|
||||
.build();
|
||||
|
||||
final var lowered = new LowerToIRVMService().lower(backend);
|
||||
|
||||
assertEquals("main", lowered.module().functions().get(0).name());
|
||||
assertEquals(9, lowered.module().functions().get(0).localSlots());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lowerMustRejectMissingQualifiedEntrypointIdentity() {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("main")
|
||||
.entryPointModuleId(new ModuleId(5))
|
||||
.modulePool(ReadOnlyList.from(new ModuleReference("app", ReadOnlyList.from("alpha"))))
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fnWithModule("main", "legacy/alpha", 0, 40, ReadOnlyList.from(ret()))))
|
||||
.build();
|
||||
|
||||
final var thrown = assertThrows(IRVMLoweringException.class, () -> new LowerToIRVMService().lower(backend));
|
||||
assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_MISSING, thrown.code());
|
||||
assertTrue(thrown.getMessage().contains("qualified entrypoint"));
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction fn(
|
||||
final String name,
|
||||
final String moduleKey,
|
||||
@ -248,6 +283,16 @@ class LowerToIRVMServiceTest {
|
||||
final int moduleId,
|
||||
final int callableId,
|
||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||
return fnWithModuleAndLocals(name, moduleKey, moduleId, callableId, 0, instructions);
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction fnWithModuleAndLocals(
|
||||
final String name,
|
||||
final String moduleKey,
|
||||
final int moduleId,
|
||||
final int callableId,
|
||||
final int localSlots,
|
||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||
return new IRBackendExecutableFunction(
|
||||
new FileId(0),
|
||||
new ModuleId(moduleId),
|
||||
@ -257,7 +302,7 @@ class LowerToIRVMServiceTest {
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
localSlots,
|
||||
0,
|
||||
4,
|
||||
instructions,
|
||||
|
||||
@ -23,6 +23,8 @@ public class IRBackend {
|
||||
@Builder.Default
|
||||
private final String entryPointCallableName = "main";
|
||||
@Builder.Default
|
||||
private final ModuleId entryPointModuleId = ModuleId.none();
|
||||
@Builder.Default
|
||||
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
||||
@Builder.Default
|
||||
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
|
||||
@ -41,6 +43,7 @@ public class IRBackend {
|
||||
|
||||
public static final class IRBackendAggregator {
|
||||
private String entryPointCallableName;
|
||||
private ModuleId entryPointModuleId = ModuleId.none();
|
||||
private final ArrayList<IRFunction> functions = new ArrayList<>();
|
||||
private final ArrayList<IRBackendExecutableFunction> executableFunctions = new ArrayList<>();
|
||||
private final ModuleTable moduleTable = new ModuleTable();
|
||||
@ -76,6 +79,13 @@ public class IRBackend {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IRBackendAggregator entryPointModuleId(final ModuleId moduleId) {
|
||||
if (moduleId != null) {
|
||||
entryPointModuleId = moduleId;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private ModuleId[] reindexModules(final ReadOnlyList<ModuleReference> localModulePool) {
|
||||
if (localModulePool == null || localModulePool.isEmpty()) {
|
||||
return new ModuleId[0];
|
||||
@ -273,6 +283,7 @@ public class IRBackend {
|
||||
return IRBackend
|
||||
.builder()
|
||||
.entryPointCallableName(resolveEntryPointCallableName())
|
||||
.entryPointModuleId(resolveEntryPointModuleId())
|
||||
.functions(ReadOnlyList.wrap(functions))
|
||||
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
||||
.modulePool(emitModulePool())
|
||||
@ -291,12 +302,18 @@ public class IRBackend {
|
||||
? "main"
|
||||
: entryPointCallableName;
|
||||
}
|
||||
|
||||
private ModuleId resolveEntryPointModuleId() {
|
||||
return entryPointModuleId == null ? ModuleId.none() : entryPointModuleId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final var sb = new StringBuilder();
|
||||
sb.append("IRBackend{entrypoint=").append(entryPointCallableName)
|
||||
.append('@')
|
||||
.append(entryPointModuleId == null || entryPointModuleId.isNone() ? "-" : entryPointModuleId.getIndex())
|
||||
.append(", functions=").append(functions.size())
|
||||
.append(", executableFunctions=").append(executableFunctions.size())
|
||||
.append(", modulePool=").append(modulePool.size())
|
||||
|
||||
@ -192,6 +192,18 @@ class IRBackendExecutableContractTest {
|
||||
|
||||
final var backend = aggregator.emit();
|
||||
assertEquals("frame", backend.getEntryPointCallableName());
|
||||
assertTrue(backend.getEntryPointModuleId().isNone());
|
||||
}
|
||||
|
||||
@Test
|
||||
void aggregatorMustEmitConfiguredEntrypointModuleId() {
|
||||
final var aggregator = IRBackend.aggregator();
|
||||
aggregator.entryPointCallableName("frame");
|
||||
aggregator.entryPointModuleId(new ModuleId(3));
|
||||
|
||||
final var backend = aggregator.emit();
|
||||
assertEquals("frame", backend.getEntryPointCallableName());
|
||||
assertEquals(3, backend.getEntryPointModuleId().getIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user