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.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -191,13 +192,26 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final var blockedModuleIds = blockedModulesByDependency(failedModuleIds, moduleDependencyGraph);
|
final var blockedModuleIds = blockedModulesByDependency(failedModuleIds, moduleDependencyGraph);
|
||||||
|
final var entryPointCallableName = PBSDefinitions.PBS.getEntryPointCallableName();
|
||||||
|
final var entryPointModuleCandidates = new LinkedHashSet<ModuleId>();
|
||||||
for (final var compiledSource : compiledSourceFiles) {
|
for (final var compiledSource : compiledSourceFiles) {
|
||||||
if (blockedModuleIds.contains(compiledSource.moduleId())) {
|
if (blockedModuleIds.contains(compiledSource.moduleId())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
irBackendAggregator.merge(compiledSource.irBackendFile());
|
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();
|
final var irBackend = irBackendAggregator.emit();
|
||||||
logs.using(log).debug("PBS frontend lowered to IR BE:\n%s".formatted(irBackend));
|
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,
|
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_DECLARATION_MISSING,
|
||||||
"frontend IRBackend entrypoint declaration is missing");
|
"frontend IRBackend entrypoint declaration is missing");
|
||||||
}
|
}
|
||||||
|
final var entryPointModuleId = backend.getEntryPointModuleId();
|
||||||
final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList());
|
final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList());
|
||||||
sorted.sort((left, right) -> {
|
sorted.sort((left, right) -> {
|
||||||
final var leftModuleKey = moduleSortKey(backend, left.moduleId(), left.moduleKey());
|
final var leftModuleKey = moduleSortKey(backend, left.moduleId(), left.moduleKey());
|
||||||
@ -314,15 +315,39 @@ public class LowerToIRVMService {
|
|||||||
}
|
}
|
||||||
return Integer.compare(left.sourceStart(), right.sourceStart());
|
return Integer.compare(left.sourceStart(), right.sourceStart());
|
||||||
});
|
});
|
||||||
final var entrypoints = sorted.stream()
|
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()))
|
.filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
|
||||||
.toList();
|
.toList();
|
||||||
|
}
|
||||||
if (entrypoints.isEmpty()) {
|
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(
|
throw new IRVMLoweringException(
|
||||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_MISSING,
|
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_MISSING,
|
||||||
"missing entrypoint callable '%s'".formatted(entryPointCallableName));
|
"missing entrypoint callable '%s'".formatted(entryPointCallableName));
|
||||||
}
|
}
|
||||||
if (entrypoints.size() > 1) {
|
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(
|
throw new IRVMLoweringException(
|
||||||
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS,
|
IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS,
|
||||||
"ambiguous entrypoint: found %d callables named '%s'".formatted(
|
"ambiguous entrypoint: found %d callables named '%s'".formatted(
|
||||||
|
|||||||
@ -222,6 +222,41 @@ class LowerToIRVMServiceTest {
|
|||||||
assertEquals("helper_in_zeta", lowered.module().functions().get(2).name());
|
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(
|
private static IRBackendExecutableFunction fn(
|
||||||
final String name,
|
final String name,
|
||||||
final String moduleKey,
|
final String moduleKey,
|
||||||
@ -248,6 +283,16 @@ class LowerToIRVMServiceTest {
|
|||||||
final int moduleId,
|
final int moduleId,
|
||||||
final int callableId,
|
final int callableId,
|
||||||
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
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(
|
return new IRBackendExecutableFunction(
|
||||||
new FileId(0),
|
new FileId(0),
|
||||||
new ModuleId(moduleId),
|
new ModuleId(moduleId),
|
||||||
@ -257,7 +302,7 @@ class LowerToIRVMServiceTest {
|
|||||||
0,
|
0,
|
||||||
10,
|
10,
|
||||||
0,
|
0,
|
||||||
0,
|
localSlots,
|
||||||
0,
|
0,
|
||||||
4,
|
4,
|
||||||
instructions,
|
instructions,
|
||||||
|
|||||||
@ -23,6 +23,8 @@ public class IRBackend {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private final String entryPointCallableName = "main";
|
private final String entryPointCallableName = "main";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
|
private final ModuleId entryPointModuleId = ModuleId.none();
|
||||||
|
@Builder.Default
|
||||||
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
|
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
|
||||||
@ -41,6 +43,7 @@ public class IRBackend {
|
|||||||
|
|
||||||
public static final class IRBackendAggregator {
|
public static final class IRBackendAggregator {
|
||||||
private String entryPointCallableName;
|
private String entryPointCallableName;
|
||||||
|
private ModuleId entryPointModuleId = ModuleId.none();
|
||||||
private final ArrayList<IRFunction> functions = new ArrayList<>();
|
private final ArrayList<IRFunction> functions = new ArrayList<>();
|
||||||
private final ArrayList<IRBackendExecutableFunction> executableFunctions = new ArrayList<>();
|
private final ArrayList<IRBackendExecutableFunction> executableFunctions = new ArrayList<>();
|
||||||
private final ModuleTable moduleTable = new ModuleTable();
|
private final ModuleTable moduleTable = new ModuleTable();
|
||||||
@ -76,6 +79,13 @@ public class IRBackend {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRBackendAggregator entryPointModuleId(final ModuleId moduleId) {
|
||||||
|
if (moduleId != null) {
|
||||||
|
entryPointModuleId = moduleId;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private ModuleId[] reindexModules(final ReadOnlyList<ModuleReference> localModulePool) {
|
private ModuleId[] reindexModules(final ReadOnlyList<ModuleReference> localModulePool) {
|
||||||
if (localModulePool == null || localModulePool.isEmpty()) {
|
if (localModulePool == null || localModulePool.isEmpty()) {
|
||||||
return new ModuleId[0];
|
return new ModuleId[0];
|
||||||
@ -273,6 +283,7 @@ public class IRBackend {
|
|||||||
return IRBackend
|
return IRBackend
|
||||||
.builder()
|
.builder()
|
||||||
.entryPointCallableName(resolveEntryPointCallableName())
|
.entryPointCallableName(resolveEntryPointCallableName())
|
||||||
|
.entryPointModuleId(resolveEntryPointModuleId())
|
||||||
.functions(ReadOnlyList.wrap(functions))
|
.functions(ReadOnlyList.wrap(functions))
|
||||||
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
||||||
.modulePool(emitModulePool())
|
.modulePool(emitModulePool())
|
||||||
@ -291,12 +302,18 @@ public class IRBackend {
|
|||||||
? "main"
|
? "main"
|
||||||
: entryPointCallableName;
|
: entryPointCallableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ModuleId resolveEntryPointModuleId() {
|
||||||
|
return entryPointModuleId == null ? ModuleId.none() : entryPointModuleId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final var sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
sb.append("IRBackend{entrypoint=").append(entryPointCallableName)
|
sb.append("IRBackend{entrypoint=").append(entryPointCallableName)
|
||||||
|
.append('@')
|
||||||
|
.append(entryPointModuleId == null || entryPointModuleId.isNone() ? "-" : entryPointModuleId.getIndex())
|
||||||
.append(", functions=").append(functions.size())
|
.append(", functions=").append(functions.size())
|
||||||
.append(", executableFunctions=").append(executableFunctions.size())
|
.append(", executableFunctions=").append(executableFunctions.size())
|
||||||
.append(", modulePool=").append(modulePool.size())
|
.append(", modulePool=").append(modulePool.size())
|
||||||
|
|||||||
@ -192,6 +192,18 @@ class IRBackendExecutableContractTest {
|
|||||||
|
|
||||||
final var backend = aggregator.emit();
|
final var backend = aggregator.emit();
|
||||||
assertEquals("frame", backend.getEntryPointCallableName());
|
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
|
@Test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user