implements PR-08.2

This commit is contained in:
bQUARKz 2026-03-09 14:22:22 +00:00
parent 40188b67ab
commit 0490f64870
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
11 changed files with 520 additions and 23 deletions

View File

@ -19,6 +19,7 @@ import p.studio.compiler.source.identifiers.CallableShapeId;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId; import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.identifiers.NameId; import p.studio.compiler.source.identifiers.NameId;
import p.studio.compiler.source.identifiers.TypeSurfaceId; import p.studio.compiler.source.identifiers.TypeSurfaceId;
import p.studio.compiler.source.tables.CallableShapeTable; import p.studio.compiler.source.tables.CallableShapeTable;
@ -26,6 +27,7 @@ import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.CallableTable; import p.studio.compiler.source.tables.CallableTable;
import p.studio.compiler.source.tables.IntrinsicReference; import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.source.tables.IntrinsicTable; import p.studio.compiler.source.tables.IntrinsicTable;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.compiler.source.tables.NameTable; import p.studio.compiler.source.tables.NameTable;
import p.studio.compiler.source.tables.TypeSurfaceTable; import p.studio.compiler.source.tables.TypeSurfaceTable;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
@ -71,7 +73,16 @@ public final class PbsFrontendCompiler {
? PbsParser.ParseMode.INTERFACE_MODULE ? PbsParser.ParseMode.INTERFACE_MODULE
: PbsParser.ParseMode.ORDINARY; : PbsParser.ParseMode.ORDINARY;
final var ast = PbsParser.parse(tokens, fileId, diagnostics, parseMode); final var ast = PbsParser.parse(tokens, fileId, diagnostics, parseMode);
final var irBackendFile = compileParsedFile(fileId, ast, diagnostics, sourceKind, "", hostAdmissionContext, nameTable); final var irBackendFile = compileParsedFile(
fileId,
ast,
diagnostics,
sourceKind,
ModuleId.none(),
"",
ReadOnlyList.empty(),
hostAdmissionContext,
nameTable);
if (diagnostics.errorCount() > admissionBaseline) { if (diagnostics.errorCount() > admissionBaseline) {
return IRBackendFile.empty(fileId); return IRBackendFile.empty(fileId);
} }
@ -99,7 +110,16 @@ public final class PbsFrontendCompiler {
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final SourceKind sourceKind, final SourceKind sourceKind,
final HostAdmissionContext hostAdmissionContext) { final HostAdmissionContext hostAdmissionContext) {
return compileParsedFile(fileId, ast, diagnostics, sourceKind, "", hostAdmissionContext, new NameTable()); return compileParsedFile(
fileId,
ast,
diagnostics,
sourceKind,
ModuleId.none(),
"",
ReadOnlyList.empty(),
hostAdmissionContext,
new NameTable());
} }
public IRBackendFile compileParsedFile( public IRBackendFile compileParsedFile(
@ -109,7 +129,16 @@ public final class PbsFrontendCompiler {
final SourceKind sourceKind, final SourceKind sourceKind,
final String moduleKey, final String moduleKey,
final HostAdmissionContext hostAdmissionContext) { final HostAdmissionContext hostAdmissionContext) {
return compileParsedFile(fileId, ast, diagnostics, sourceKind, moduleKey, hostAdmissionContext, new NameTable()); return compileParsedFile(
fileId,
ast,
diagnostics,
sourceKind,
ModuleId.none(),
moduleKey,
ReadOnlyList.empty(),
hostAdmissionContext,
new NameTable());
} }
public IRBackendFile compileParsedFile( public IRBackendFile compileParsedFile(
@ -117,7 +146,9 @@ public final class PbsFrontendCompiler {
final PbsAst.File ast, final PbsAst.File ast,
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final SourceKind sourceKind, final SourceKind sourceKind,
final ModuleId moduleId,
final String moduleKey, final String moduleKey,
final ReadOnlyList<ModuleReference> modulePool,
final HostAdmissionContext hostAdmissionContext, final HostAdmissionContext hostAdmissionContext,
final NameTable nameTable) { final NameTable nameTable) {
return compileParsedFile( return compileParsedFile(
@ -125,7 +156,9 @@ public final class PbsFrontendCompiler {
ast, ast,
diagnostics, diagnostics,
sourceKind, sourceKind,
moduleId,
moduleKey, moduleKey,
modulePool,
hostAdmissionContext, hostAdmissionContext,
nameTable, nameTable,
ReadOnlyList.empty(), ReadOnlyList.empty(),
@ -138,12 +171,16 @@ public final class PbsFrontendCompiler {
final PbsAst.File ast, final PbsAst.File ast,
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final SourceKind sourceKind, final SourceKind sourceKind,
final ModuleId moduleId,
final String moduleKey, final String moduleKey,
final ReadOnlyList<ModuleReference> modulePool,
final HostAdmissionContext hostAdmissionContext, final HostAdmissionContext hostAdmissionContext,
final NameTable nameTable, final NameTable nameTable,
final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls, final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls,
final ReadOnlyList<ImportedCallableSurface> importedCallables, final ReadOnlyList<ImportedCallableSurface> importedCallables,
final IRReservedMetadata importedReservedMetadata) { final IRReservedMetadata importedReservedMetadata) {
final var effectiveModuleId = moduleId == null ? ModuleId.none() : moduleId;
final var effectiveModulePool = modulePool == null ? ReadOnlyList.<ModuleReference>empty() : modulePool;
final var effectiveNameTable = nameTable == null ? new NameTable() : nameTable; final var effectiveNameTable = nameTable == null ? new NameTable() : nameTable;
final var effectiveSupplementalTopDecls = supplementalTopDecls == null final var effectiveSupplementalTopDecls = supplementalTopDecls == null
? ReadOnlyList.<PbsAst.TopDecl>empty() ? ReadOnlyList.<PbsAst.TopDecl>empty()
@ -187,6 +224,7 @@ public final class PbsFrontendCompiler {
fileId, fileId,
ast, ast,
effectiveSupplementalTopDecls, effectiveSupplementalTopDecls,
effectiveModuleId,
moduleKey, moduleKey,
effectiveReservedMetadata, effectiveReservedMetadata,
effectiveNameTable, effectiveNameTable,
@ -200,6 +238,7 @@ public final class PbsFrontendCompiler {
functions, functions,
executableLowering.executableFunctions(), executableLowering.executableFunctions(),
reservedMetadata, reservedMetadata,
effectiveModulePool,
executableLowering.callableSignatures(), executableLowering.callableSignatures(),
executableLowering.intrinsicPool()); executableLowering.intrinsicPool());
} }
@ -221,12 +260,14 @@ public final class PbsFrontendCompiler {
final FileId fileId, final FileId fileId,
final PbsAst.File ast, final PbsAst.File ast,
final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls, final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls,
final ModuleId moduleId,
final String moduleKey, final String moduleKey,
final IRReservedMetadata reservedMetadata, final IRReservedMetadata reservedMetadata,
final NameTable nameTable, final NameTable nameTable,
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final ReadOnlyList<ImportedCallableSurface> importedCallables) { final ReadOnlyList<ImportedCallableSurface> importedCallables) {
final var normalizedModuleKey = moduleKey == null ? "" : moduleKey; final var normalizedModuleKey = moduleKey == null ? "" : moduleKey;
final var normalizedModuleId = moduleId == null ? ModuleId.none() : moduleId;
final var hostByMethodName = new HashMap<NameId, List<IRReservedMetadata.HostMethodBinding>>(); final var hostByMethodName = new HashMap<NameId, List<IRReservedMetadata.HostMethodBinding>>();
for (final var hostBinding : reservedMetadata.hostMethodBindings()) { for (final var hostBinding : reservedMetadata.hostMethodBindings()) {
hostByMethodName hostByMethodName
@ -318,6 +359,7 @@ public final class PbsFrontendCompiler {
final var declaredFn = declaredCallable.functionDecl(); final var declaredFn = declaredCallable.functionDecl();
final var callableShapeId = callableShapeId(declaredFn, typeSurfaceTable, callableShapeTable); final var callableShapeId = callableShapeId(declaredFn, typeSurfaceTable, callableShapeTable);
final var callableId = callableIdTable.register( final var callableId = callableIdTable.register(
normalizedModuleId,
normalizedModuleKey, normalizedModuleKey,
declaredCallable.callableName(), declaredCallable.callableName(),
declaredFn.parameters().size(), declaredFn.parameters().size(),
@ -333,6 +375,7 @@ public final class PbsFrontendCompiler {
} }
for (final var importedCallable : importedCallables) { for (final var importedCallable : importedCallables) {
final var callableId = callableIdTable.register( final var callableId = callableIdTable.register(
importedCallable.moduleId(),
importedCallable.moduleKey(), importedCallable.moduleKey(),
importedCallable.callableName(), importedCallable.callableName(),
importedCallable.arity(), importedCallable.arity(),
@ -359,6 +402,7 @@ public final class PbsFrontendCompiler {
localSlotByNameId.put(nameTable.register(fn.parameters().get(paramIndex).name()), paramIndex); localSlotByNameId.put(nameTable.register(fn.parameters().get(paramIndex).name()), paramIndex);
} }
final var loweringContext = new ExecutableLoweringContext( final var loweringContext = new ExecutableLoweringContext(
normalizedModuleId,
normalizedModuleKey, normalizedModuleKey,
diagnostics, diagnostics,
nameTable, nameTable,
@ -401,6 +445,7 @@ public final class PbsFrontendCompiler {
final var end = safeToInt(fn.span().getEnd()); final var end = safeToInt(fn.span().getEnd());
executableFunctions.add(new IRBackendExecutableFunction( executableFunctions.add(new IRBackendExecutableFunction(
fileId, fileId,
normalizedModuleId,
normalizedModuleKey, normalizedModuleKey,
callable.callableName(), callable.callableName(),
functionCallableId, functionCallableId,
@ -921,6 +966,7 @@ public final class PbsFrontendCompiler {
final var calleeCallableId = callableCandidates.getFirst(); final var calleeCallableId = callableCandidates.getFirst();
context.instructions().add(new IRBackendExecutableFunction.Instruction( context.instructions().add(new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.CALL_FUNC, IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
context.moduleId(),
context.moduleKey(), context.moduleKey(),
calleeIdentity.primaryCallableDisplayName(), calleeIdentity.primaryCallableDisplayName(),
calleeCallableId, calleeCallableId,
@ -1292,6 +1338,7 @@ public final class PbsFrontendCompiler {
} }
private static final class ExecutableLoweringContext { private static final class ExecutableLoweringContext {
private final ModuleId moduleId;
private final String moduleKey; private final String moduleKey;
private final DiagnosticSink diagnostics; private final DiagnosticSink diagnostics;
private final NameTable nameTable; private final NameTable nameTable;
@ -1308,6 +1355,7 @@ public final class PbsFrontendCompiler {
private int nextLabelId = 0; private int nextLabelId = 0;
private ExecutableLoweringContext( private ExecutableLoweringContext(
final ModuleId moduleId,
final String moduleKey, final String moduleKey,
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final NameTable nameTable, final NameTable nameTable,
@ -1319,6 +1367,7 @@ public final class PbsFrontendCompiler {
final Map<CallableId, Integer> returnSlotsByCallableId, final Map<CallableId, Integer> returnSlotsByCallableId,
final IntrinsicTable intrinsicIdTable, final IntrinsicTable intrinsicIdTable,
final Map<NameId, Integer> localSlotByNameId) { final Map<NameId, Integer> localSlotByNameId) {
this.moduleId = moduleId == null ? ModuleId.none() : moduleId;
this.moduleKey = moduleKey; this.moduleKey = moduleKey;
this.diagnostics = diagnostics; this.diagnostics = diagnostics;
this.nameTable = nameTable; this.nameTable = nameTable;
@ -1332,6 +1381,10 @@ public final class PbsFrontendCompiler {
this.localSlotByNameId = localSlotByNameId == null ? Map.of() : localSlotByNameId; this.localSlotByNameId = localSlotByNameId == null ? Map.of() : localSlotByNameId;
} }
private ModuleId moduleId() {
return moduleId;
}
private String moduleKey() { private String moduleKey() {
return moduleKey; return moduleKey;
} }
@ -1440,11 +1493,15 @@ public final class PbsFrontendCompiler {
} }
public record ImportedCallableSurface( public record ImportedCallableSurface(
ModuleId moduleId,
String moduleKey, String moduleKey,
String callableName, String callableName,
int arity, int arity,
int returnSlots, int returnSlots,
String shapeSurface) { String shapeSurface) {
public ImportedCallableSurface {
moduleId = moduleId == null ? ModuleId.none() : moduleId;
}
} }
private static final class ExecutableLoweringAnalysisException extends RuntimeException { private static final class ExecutableLoweringAnalysisException extends RuntimeException {

View File

@ -159,6 +159,7 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
markModulesWithLinkingErrors(diagnostics, moduleIdByFile, failedModuleIds); markModulesWithLinkingErrors(diagnostics, moduleIdByFile, failedModuleIds);
final var moduleDependencyGraph = buildModuleDependencyGraph(parsedSourceFiles, moduleTable); final var moduleDependencyGraph = buildModuleDependencyGraph(parsedSourceFiles, moduleTable);
final var importedSemanticContexts = buildImportedSemanticContexts(parsedSourceFiles, moduleTable); final var importedSemanticContexts = buildImportedSemanticContexts(parsedSourceFiles, moduleTable);
final var canonicalModulePool = emitModulePool(moduleTable);
final var compiledSourceFiles = new ArrayList<CompiledSourceFile>(parsedSourceFiles.size()); final var compiledSourceFiles = new ArrayList<CompiledSourceFile>(parsedSourceFiles.size());
for (final var parsedSource : parsedSourceFiles) { for (final var parsedSource : parsedSourceFiles) {
@ -175,7 +176,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
parsedSource.ast(), parsedSource.ast(),
diagnostics, diagnostics,
parsedSource.sourceKind(), parsedSource.sourceKind(),
parsedSource.moduleId(),
renderModuleKey(moduleTable, parsedSource.moduleId()), renderModuleKey(moduleTable, parsedSource.moduleId()),
canonicalModulePool,
ctx.hostAdmissionContext(), ctx.hostAdmissionContext(),
nameTable, nameTable,
importedSemanticContext.supplementalTopDecls(), importedSemanticContext.supplementalTopDecls(),
@ -431,6 +434,7 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
importedCallables, importedCallables,
importedCallableKeys, importedCallableKeys,
new PbsFrontendCompiler.ImportedCallableSurface( new PbsFrontendCompiler.ImportedCallableSurface(
importedModuleId,
importedModuleKey, importedModuleKey,
localName + "." + method.name(), localName + "." + method.name(),
method.parameters().size(), method.parameters().size(),
@ -444,6 +448,7 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
importedCallables, importedCallables,
importedCallableKeys, importedCallableKeys,
new PbsFrontendCompiler.ImportedCallableSurface( new PbsFrontendCompiler.ImportedCallableSurface(
importedModuleId,
importedModuleKey, importedModuleKey,
localName, localName,
functionDecl.parameters().size(), functionDecl.parameters().size(),
@ -793,6 +798,14 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
return moduleReference.project() + ":" + String.join("/", moduleReference.pathSegments().asList()); return moduleReference.project() + ":" + String.join("/", moduleReference.pathSegments().asList());
} }
private ReadOnlyList<ModuleReference> emitModulePool(final ModuleTable moduleTable) {
final var pool = new ArrayList<ModuleReference>(moduleTable.size());
for (final var moduleId : moduleTable.identifiers()) {
pool.add(moduleTable.get(moduleId));
}
return ReadOnlyList.wrap(pool);
}
private static final class MutableModuleUnit { private static final class MutableModuleUnit {
private final ArrayList<PbsModuleVisibilityValidator.SourceFile> sources = new ArrayList<>(); private final ArrayList<PbsModuleVisibilityValidator.SourceFile> sources = new ArrayList<>();
private final ArrayList<PbsModuleVisibilityValidator.BarrelFile> barrels = new ArrayList<>(); private final ArrayList<PbsModuleVisibilityValidator.BarrelFile> barrels = new ArrayList<>();

View File

@ -6,19 +6,15 @@ import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction; import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span; import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.StringJoiner;
public class LowerToIRVMService { public class LowerToIRVMService {
private static final Comparator<IRBackendExecutableFunction> FUNCTION_ORDER = Comparator
.comparing(IRBackendExecutableFunction::moduleKey)
.thenComparing(IRBackendExecutableFunction::callableName)
.thenComparingInt(function -> function.callableId().getIndex())
.thenComparingInt(IRBackendExecutableFunction::sourceStart);
private final IRVMValidator validator; private final IRVMValidator validator;
public LowerToIRVMService() { public LowerToIRVMService() {
@ -301,7 +297,23 @@ public class LowerToIRVMService {
"frontend IRBackend entrypoint declaration is missing"); "frontend IRBackend entrypoint declaration is missing");
} }
final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList()); final var sorted = new ArrayList<>(backend.getExecutableFunctions().asList());
sorted.sort(FUNCTION_ORDER); sorted.sort((left, right) -> {
final var leftModuleKey = moduleSortKey(backend, left.moduleId(), left.moduleKey());
final var rightModuleKey = moduleSortKey(backend, right.moduleId(), right.moduleKey());
final var moduleCmp = leftModuleKey.compareTo(rightModuleKey);
if (moduleCmp != 0) {
return moduleCmp;
}
final var nameCmp = left.callableName().compareTo(right.callableName());
if (nameCmp != 0) {
return nameCmp;
}
final var idCmp = Integer.compare(left.callableId().getIndex(), right.callableId().getIndex());
if (idCmp != 0) {
return idCmp;
}
return Integer.compare(left.sourceStart(), right.sourceStart());
});
final var entrypoints = sorted.stream() final var entrypoints = sorted.stream()
.filter(candidate -> entryPointCallableName.equals(candidate.callableName())) .filter(candidate -> entryPointCallableName.equals(candidate.callableName()))
.toList(); .toList();
@ -328,6 +340,27 @@ public class LowerToIRVMService {
return ReadOnlyList.wrap(ordered); return ReadOnlyList.wrap(ordered);
} }
private String moduleSortKey(
final IRBackend backend,
final ModuleId moduleId,
final String fallbackModuleKey) {
if (moduleId != null && !moduleId.isNone()) {
final var index = moduleId.getIndex();
if (index >= 0 && index < backend.getModulePool().size()) {
return canonicalModuleSortKey(backend.getModulePool().get(index));
}
}
return fallbackModuleKey == null ? "" : fallbackModuleKey;
}
private String canonicalModuleSortKey(final ModuleReference reference) {
final var joiner = new StringJoiner("/", reference.project() + ":", "");
for (final var segment : reference.pathSegments()) {
joiner.add(segment);
}
return joiner.toString();
}
private BytecodeModule.SourceSpan toBytecodeSpan( private BytecodeModule.SourceSpan toBytecodeSpan(
final int fallbackFileId, final int fallbackFileId,
final Span span) { final Span span) {

View File

@ -7,7 +7,9 @@ import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId; import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.IntrinsicReference; import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -199,6 +201,27 @@ class LowerToIRVMServiceTest {
assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS, thrown.code()); assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_ENTRYPOINT_AMBIGUOUS, thrown.code());
} }
@Test
void lowerMustUseModulePoolCanonicalIdentityForNonEntrypointOrdering() {
final var backend = IRBackend.builder()
.entryPointCallableName("frame")
.modulePool(ReadOnlyList.from(
new ModuleReference("app", ReadOnlyList.from("alpha")),
new ModuleReference("app", ReadOnlyList.from("zeta"))))
.executableFunctions(ReadOnlyList.from(
fnWithModule("helper_in_zeta", "legacy/zeta", 1, 21, ReadOnlyList.from(ret())),
fnWithModule("frame", "legacy/zeta", 1, 20, ReadOnlyList.from(ret())),
fnWithModule("helper_in_alpha", "legacy/alpha", 0, 22, ReadOnlyList.from(ret()))))
.build();
final var lowered = new LowerToIRVMService().lower(backend);
assertEquals(3, lowered.module().functions().size());
assertEquals("frame", lowered.module().functions().get(0).name());
assertEquals("helper_in_alpha", lowered.module().functions().get(1).name());
assertEquals("helper_in_zeta", lowered.module().functions().get(2).name());
}
private static IRBackendExecutableFunction fn( private static IRBackendExecutableFunction fn(
final String name, final String name,
final String moduleKey, final String moduleKey,
@ -219,6 +242,28 @@ class LowerToIRVMServiceTest {
Span.none()); Span.none());
} }
private static IRBackendExecutableFunction fnWithModule(
final String name,
final String moduleKey,
final int moduleId,
final int callableId,
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
return new IRBackendExecutableFunction(
new FileId(0),
new ModuleId(moduleId),
moduleKey,
name,
new CallableId(callableId),
0,
10,
0,
0,
0,
4,
instructions,
Span.none());
}
private static IRBackendExecutableFunction.Instruction ret() { private static IRBackendExecutableFunction.Instruction ret() {
return new IRBackendExecutableFunction.Instruction( return new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.RET, IRBackendExecutableFunction.InstructionKind.RET,

View File

@ -1,7 +1,17 @@
package p.studio.compiler.source.identifiers; package p.studio.compiler.source.identifiers;
public class ModuleId extends SourceIdentifier { public class ModuleId extends SourceIdentifier {
public static final ModuleId NONE = new ModuleId(-1);
public ModuleId(int id) { public ModuleId(int id) {
super(id); super(id);
} }
public static ModuleId none() {
return NONE;
}
public boolean isNone() {
return this == NONE;
}
} }

View File

@ -1,14 +1,29 @@
package p.studio.compiler.source.tables; package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.ModuleId;
import java.util.Objects; import java.util.Objects;
public record CallableSignatureRef( public record CallableSignatureRef(
ModuleId moduleId,
String moduleKey, String moduleKey,
String callableName, String callableName,
int arity, int arity,
String typeShape) { String typeShape) {
public CallableSignatureRef(
final String moduleKey,
final String callableName,
final int arity,
final String typeShape) {
this(ModuleId.none(), moduleKey, callableName, arity, typeShape);
}
public CallableSignatureRef { public CallableSignatureRef {
moduleId = moduleId == null ? ModuleId.none() : moduleId;
if (!moduleId.isNone()) {
moduleId.getIndex();
}
moduleKey = moduleKey == null ? "" : moduleKey; moduleKey = moduleKey == null ? "" : moduleKey;
callableName = Objects.requireNonNull(callableName, "callableName"); callableName = Objects.requireNonNull(callableName, "callableName");
typeShape = typeShape == null ? "" : typeShape; typeShape = typeShape == null ? "" : typeShape;

View File

@ -1,6 +1,7 @@
package p.studio.compiler.source.tables; package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.ModuleId;
public class CallableTable extends InternTable<CallableId, CallableSignatureRef> implements CallableTableReader { public class CallableTable extends InternTable<CallableId, CallableSignatureRef> implements CallableTableReader {
@ -13,6 +14,15 @@ public class CallableTable extends InternTable<CallableId, CallableSignatureRef>
final String callableName, final String callableName,
final int arity, final int arity,
final String typeShape) { final String typeShape) {
return register(new CallableSignatureRef(moduleKey, callableName, arity, typeShape)); return register(new CallableSignatureRef(ModuleId.none(), moduleKey, callableName, arity, typeShape));
}
public CallableId register(
final ModuleId moduleId,
final String moduleKey,
final String callableName,
final int arity,
final String typeShape) {
return register(new CallableSignatureRef(moduleId, moduleKey, callableName, arity, typeShape));
} }
} }

View File

@ -4,14 +4,18 @@ import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.IntrinsicId; import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.CallableSignatureRef; import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.CallableTable; import p.studio.compiler.source.tables.CallableTable;
import p.studio.compiler.source.tables.IntrinsicReference; import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.source.tables.IntrinsicTable; import p.studio.compiler.source.tables.IntrinsicTable;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.compiler.source.tables.ModuleTable;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
@Builder @Builder
@Getter @Getter
@ -23,6 +27,8 @@ public class IRBackend {
@Builder.Default @Builder.Default
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty(); private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
@Builder.Default @Builder.Default
private final ReadOnlyList<ModuleReference> modulePool = ReadOnlyList.empty();
@Builder.Default
private final ReadOnlyList<CallableSignatureRef> callableSignatures = ReadOnlyList.empty(); private final ReadOnlyList<CallableSignatureRef> callableSignatures = ReadOnlyList.empty();
@Builder.Default @Builder.Default
private final ReadOnlyList<IntrinsicReference> intrinsicPool = ReadOnlyList.empty(); private final ReadOnlyList<IntrinsicReference> intrinsicPool = ReadOnlyList.empty();
@ -37,6 +43,7 @@ public class IRBackend {
private String entryPointCallableName; private String entryPointCallableName;
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 CallableTable callableTable = new CallableTable(); private final CallableTable callableTable = new CallableTable();
private final IntrinsicTable intrinsicTable = new IntrinsicTable(); private final IntrinsicTable intrinsicTable = new IntrinsicTable();
private final ArrayList<IRReservedMetadata.HostMethodBinding> hostMethodBindings = new ArrayList<>(); private final ArrayList<IRReservedMetadata.HostMethodBinding> hostMethodBindings = new ArrayList<>();
@ -49,10 +56,11 @@ public class IRBackend {
return; return;
} }
functions.addAll(backendFile.functions().asList()); functions.addAll(backendFile.functions().asList());
final var callableRemap = reindexCallables(backendFile.callableSignatures()); final var moduleRemap = reindexModules(backendFile.modulePool());
final var callableRemap = reindexCallables(backendFile.callableSignatures(), moduleRemap);
final var intrinsicRemap = reindexIntrinsics(backendFile.intrinsicPool()); final var intrinsicRemap = reindexIntrinsics(backendFile.intrinsicPool());
for (final var function : backendFile.executableFunctions()) { for (final var function : backendFile.executableFunctions()) {
executableFunctions.add(remapExecutableFunction(function, callableRemap, intrinsicRemap)); executableFunctions.add(remapExecutableFunction(function, moduleRemap, callableRemap, intrinsicRemap));
} }
final var metadata = backendFile.reservedMetadata(); final var metadata = backendFile.reservedMetadata();
hostMethodBindings.addAll(metadata.hostMethodBindings().asList()); hostMethodBindings.addAll(metadata.hostMethodBindings().asList());
@ -68,22 +76,52 @@ public class IRBackend {
return this; return this;
} }
private CallableId[] reindexCallables(final ReadOnlyList<CallableSignatureRef> localCallableSignatures) { private ModuleId[] reindexModules(final ReadOnlyList<ModuleReference> localModulePool) {
if (localModulePool == null || localModulePool.isEmpty()) {
return new ModuleId[0];
}
final var remap = new ModuleId[localModulePool.size()];
for (var i = 0; i < localModulePool.size(); i++) {
remap[i] = moduleTable.register(localModulePool.get(i));
}
return remap;
}
private CallableId[] reindexCallables(
final ReadOnlyList<CallableSignatureRef> localCallableSignatures,
final ModuleId[] moduleRemap) {
if (localCallableSignatures == null || localCallableSignatures.isEmpty()) { if (localCallableSignatures == null || localCallableSignatures.isEmpty()) {
return new CallableId[0]; return new CallableId[0];
} }
final var remap = new CallableId[localCallableSignatures.size()]; final var remap = new CallableId[localCallableSignatures.size()];
for (var i = 0; i < localCallableSignatures.size(); i++) { for (var i = 0; i < localCallableSignatures.size(); i++) {
remap[i] = callableTable.register(localCallableSignatures.get(i)); final var signature = localCallableSignatures.get(i);
final var remappedModuleId = remapModuleId(
signature.moduleId(),
signature.moduleKey(),
moduleRemap,
"callable signature");
remap[i] = callableTable.register(
remappedModuleId,
signature.moduleKey(),
signature.callableName(),
signature.arity(),
signature.typeShape());
} }
return remap; return remap;
} }
private IRBackendExecutableFunction remapExecutableFunction( private IRBackendExecutableFunction remapExecutableFunction(
final IRBackendExecutableFunction function, final IRBackendExecutableFunction function,
final ModuleId[] moduleRemap,
final CallableId[] callableRemap, final CallableId[] callableRemap,
final IntrinsicId[] intrinsicRemap) { final IntrinsicId[] intrinsicRemap) {
final var remappedInstructions = new ArrayList<IRBackendExecutableFunction.Instruction>(function.instructions().size()); final var remappedInstructions = new ArrayList<IRBackendExecutableFunction.Instruction>(function.instructions().size());
final var remappedFunctionModuleId = remapModuleId(
function.moduleId(),
function.moduleKey(),
moduleRemap,
"function");
for (final var instruction : function.instructions()) { for (final var instruction : function.instructions()) {
final CallableId remappedCallee; final CallableId remappedCallee;
if (instruction.calleeCallableId() == null) { if (instruction.calleeCallableId() == null) {
@ -101,8 +139,14 @@ public class IRBackend {
} else { } else {
remappedIntrinsic = instruction.intrinsicCall(); remappedIntrinsic = instruction.intrinsicCall();
} }
final var remappedCalleeModuleId = remapModuleId(
instruction.calleeModuleId(),
instruction.calleeModuleKey(),
moduleRemap,
"callee");
remappedInstructions.add(new IRBackendExecutableFunction.Instruction( remappedInstructions.add(new IRBackendExecutableFunction.Instruction(
instruction.kind(), instruction.kind(),
remappedCalleeModuleId,
instruction.calleeModuleKey(), instruction.calleeModuleKey(),
instruction.calleeCallableName(), instruction.calleeCallableName(),
remappedCallee, remappedCallee,
@ -116,6 +160,7 @@ public class IRBackend {
} }
return new IRBackendExecutableFunction( return new IRBackendExecutableFunction(
function.fileId(), function.fileId(),
remappedFunctionModuleId,
function.moduleKey(), function.moduleKey(),
function.callableName(), function.callableName(),
remapCallableId(function.callableId(), callableRemap, "function"), remapCallableId(function.callableId(), callableRemap, "function"),
@ -129,6 +174,45 @@ public class IRBackend {
function.span()); function.span());
} }
private ModuleId remapModuleId(
final ModuleId localModuleId,
final String moduleKey,
final ModuleId[] moduleRemap,
final String label) {
if (localModuleId != null && !localModuleId.isNone()) {
final var localIndex = localModuleId.getIndex();
if (localIndex < 0 || localIndex >= moduleRemap.length) {
throw new IllegalArgumentException("invalid local " + label + " module id: " + localModuleId);
}
return moduleRemap[localIndex];
}
final var fallbackReference = moduleReferenceFromKey(moduleKey);
if (fallbackReference != null) {
return moduleTable.register(fallbackReference);
}
return ModuleId.none();
}
private ModuleReference moduleReferenceFromKey(final String moduleKey) {
if (moduleKey == null || moduleKey.isBlank()) {
return null;
}
final var separator = moduleKey.indexOf(':');
if (separator <= 0) {
return null;
}
final var project = moduleKey.substring(0, separator).trim();
final var rawPath = moduleKey.substring(separator + 1).trim();
if (project.isBlank()) {
return null;
}
if (rawPath.isBlank()) {
return new ModuleReference(project, ReadOnlyList.empty());
}
final var segments = List.of(rawPath.split("/"));
return new ModuleReference(project, ReadOnlyList.wrap(segments));
}
private CallableId remapCallableId( private CallableId remapCallableId(
final CallableId localCallableId, final CallableId localCallableId,
final CallableId[] callableRemap, final CallableId[] callableRemap,
@ -169,6 +253,14 @@ public class IRBackend {
return ReadOnlyList.wrap(signatures); return ReadOnlyList.wrap(signatures);
} }
private ReadOnlyList<ModuleReference> emitModulePool() {
final var modules = new ArrayList<ModuleReference>(moduleTable.size());
for (final var moduleId : moduleTable.identifiers()) {
modules.add(moduleTable.get(moduleId));
}
return ReadOnlyList.wrap(modules);
}
private ReadOnlyList<IntrinsicReference> emitIntrinsicPool() { private ReadOnlyList<IntrinsicReference> emitIntrinsicPool() {
final var pool = new ArrayList<IntrinsicReference>(intrinsicTable.size()); final var pool = new ArrayList<IntrinsicReference>(intrinsicTable.size());
for (final var intrinsicId : intrinsicTable.identifiers()) { for (final var intrinsicId : intrinsicTable.identifiers()) {
@ -183,6 +275,7 @@ public class IRBackend {
.entryPointCallableName(resolveEntryPointCallableName()) .entryPointCallableName(resolveEntryPointCallableName())
.functions(ReadOnlyList.wrap(functions)) .functions(ReadOnlyList.wrap(functions))
.executableFunctions(ReadOnlyList.wrap(executableFunctions)) .executableFunctions(ReadOnlyList.wrap(executableFunctions))
.modulePool(emitModulePool())
.callableSignatures(emitCallableSignatures()) .callableSignatures(emitCallableSignatures())
.intrinsicPool(emitIntrinsicPool()) .intrinsicPool(emitIntrinsicPool())
.reservedMetadata(new IRReservedMetadata( .reservedMetadata(new IRReservedMetadata(
@ -206,6 +299,7 @@ public class IRBackend {
sb.append("IRBackend{entrypoint=").append(entryPointCallableName) sb.append("IRBackend{entrypoint=").append(entryPointCallableName)
.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(", callableSignatures=").append(callableSignatures.size()) .append(", callableSignatures=").append(callableSignatures.size())
.append(", intrinsicPool=").append(intrinsicPool.size()) .append(", intrinsicPool=").append(intrinsicPool.size())
.append(", hostBindings=").append(reservedMetadata.hostMethodBindings().size()) .append(", hostBindings=").append(reservedMetadata.hostMethodBindings().size())

View File

@ -4,12 +4,14 @@ import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId; import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.util.Objects; import java.util.Objects;
public record IRBackendExecutableFunction( public record IRBackendExecutableFunction(
FileId fileId, FileId fileId,
ModuleId moduleId,
String moduleKey, String moduleKey,
String callableName, String callableName,
CallableId callableId, CallableId callableId,
@ -22,8 +24,41 @@ public record IRBackendExecutableFunction(
ReadOnlyList<Instruction> instructions, ReadOnlyList<Instruction> instructions,
Span span) { Span span) {
public IRBackendExecutableFunction(
final FileId fileId,
final String moduleKey,
final String callableName,
final CallableId callableId,
final int sourceStart,
final int sourceEnd,
final int paramSlots,
final int localSlots,
final int returnSlots,
final int maxStackSlots,
final ReadOnlyList<Instruction> instructions,
final Span span) {
this(
fileId,
ModuleId.none(),
moduleKey,
callableName,
callableId,
sourceStart,
sourceEnd,
paramSlots,
localSlots,
returnSlots,
maxStackSlots,
instructions,
span);
}
public IRBackendExecutableFunction { public IRBackendExecutableFunction {
fileId = Objects.requireNonNull(fileId, "fileId"); fileId = Objects.requireNonNull(fileId, "fileId");
moduleId = moduleId == null ? ModuleId.none() : moduleId;
if (!moduleId.isNone()) {
moduleId.getIndex();
}
moduleKey = moduleKey == null ? "" : moduleKey; moduleKey = moduleKey == null ? "" : moduleKey;
callableName = Objects.requireNonNull(callableName, "callableName"); callableName = Objects.requireNonNull(callableName, "callableName");
if (callableName.isBlank()) { if (callableName.isBlank()) {
@ -52,6 +87,7 @@ public record IRBackendExecutableFunction(
public record Instruction( public record Instruction(
InstructionKind kind, InstructionKind kind,
ModuleId calleeModuleId,
String calleeModuleKey, String calleeModuleKey,
String calleeCallableName, String calleeCallableName,
CallableId calleeCallableId, CallableId calleeCallableId,
@ -64,13 +100,78 @@ public record IRBackendExecutableFunction(
Span span) { Span span) {
public Instruction( public Instruction(
final InstructionKind kind, final InstructionKind kind,
final ModuleId calleeModuleId,
final String calleeModuleKey, final String calleeModuleKey,
final String calleeCallableName, final String calleeCallableName,
final CallableId calleeCallableId, final CallableId calleeCallableId,
final HostCallMetadata hostCall, final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall, final IntrinsicCallMetadata intrinsicCall,
final Span span) { final Span span) {
this(kind, calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, null, null, span); this(kind, calleeModuleId, calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, null, null, span);
}
public Instruction(
final InstructionKind kind,
final ModuleId calleeModuleId,
final String calleeModuleKey,
final String calleeCallableName,
final CallableId calleeCallableId,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Integer expectedArgSlots,
final Integer expectedRetSlots,
final Span span) {
this(kind, calleeModuleId, calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span);
}
public Instruction(
final InstructionKind kind,
final ModuleId calleeModuleId,
final String calleeModuleKey,
final String calleeCallableName,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Span span) {
this(kind, calleeModuleId, calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, null, null, span);
}
public Instruction(
final InstructionKind kind,
final ModuleId calleeModuleId,
final String calleeModuleKey,
final String calleeCallableName,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Integer expectedArgSlots,
final Integer expectedRetSlots,
final Span span) {
this(kind, calleeModuleId, calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span);
}
public Instruction(
final InstructionKind kind,
final String calleeModuleKey,
final String calleeCallableName,
final CallableId calleeCallableId,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final String label,
final String targetLabel,
final Integer expectedArgSlots,
final Integer expectedRetSlots,
final Span span) {
this(kind, ModuleId.none(), calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, label, targetLabel, expectedArgSlots, expectedRetSlots, span);
}
public Instruction(
final InstructionKind kind,
final String calleeModuleKey,
final String calleeCallableName,
final CallableId calleeCallableId,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Span span) {
this(kind, ModuleId.none(), calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, null, null, span);
} }
public Instruction( public Instruction(
@ -83,7 +184,7 @@ public record IRBackendExecutableFunction(
final Integer expectedArgSlots, final Integer expectedArgSlots,
final Integer expectedRetSlots, final Integer expectedRetSlots,
final Span span) { final Span span) {
this(kind, calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span); this(kind, ModuleId.none(), calleeModuleKey, calleeCallableName, calleeCallableId, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span);
} }
public Instruction( public Instruction(
@ -93,7 +194,7 @@ public record IRBackendExecutableFunction(
final HostCallMetadata hostCall, final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall, final IntrinsicCallMetadata intrinsicCall,
final Span span) { final Span span) {
this(kind, calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, null, null, span); this(kind, ModuleId.none(), calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, null, null, span);
} }
public Instruction( public Instruction(
@ -105,12 +206,16 @@ public record IRBackendExecutableFunction(
final Integer expectedArgSlots, final Integer expectedArgSlots,
final Integer expectedRetSlots, final Integer expectedRetSlots,
final Span span) { final Span span) {
this(kind, calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span); this(kind, ModuleId.none(), calleeModuleKey, calleeCallableName, null, hostCall, intrinsicCall, null, null, expectedArgSlots, expectedRetSlots, span);
} }
public Instruction { public Instruction {
Objects.requireNonNull(kind, "kind"); Objects.requireNonNull(kind, "kind");
span = span == null ? Span.none() : span; span = span == null ? Span.none() : span;
calleeModuleId = calleeModuleId == null ? ModuleId.none() : calleeModuleId;
if (!calleeModuleId.isNone()) {
calleeModuleId.getIndex();
}
calleeModuleKey = calleeModuleKey == null ? "" : calleeModuleKey; calleeModuleKey = calleeModuleKey == null ? "" : calleeModuleKey;
calleeCallableName = calleeCallableName == null ? "" : calleeCallableName; calleeCallableName = calleeCallableName == null ? "" : calleeCallableName;
label = label == null ? "" : label; label = label == null ? "" : label;

View File

@ -3,6 +3,7 @@ package p.studio.compiler.models;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.tables.CallableSignatureRef; import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.IntrinsicReference; import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.util.Objects; import java.util.Objects;
@ -12,6 +13,7 @@ public record IRBackendFile(
ReadOnlyList<IRFunction> functions, ReadOnlyList<IRFunction> functions,
ReadOnlyList<IRBackendExecutableFunction> executableFunctions, ReadOnlyList<IRBackendExecutableFunction> executableFunctions,
IRReservedMetadata reservedMetadata, IRReservedMetadata reservedMetadata,
ReadOnlyList<ModuleReference> modulePool,
ReadOnlyList<CallableSignatureRef> callableSignatures, ReadOnlyList<CallableSignatureRef> callableSignatures,
ReadOnlyList<IntrinsicReference> intrinsicPool) { ReadOnlyList<IntrinsicReference> intrinsicPool) {
public IRBackendFile { public IRBackendFile {
@ -19,6 +21,7 @@ public record IRBackendFile(
functions = functions == null ? ReadOnlyList.empty() : functions; functions = functions == null ? ReadOnlyList.empty() : functions;
executableFunctions = executableFunctions == null ? ReadOnlyList.empty() : executableFunctions; executableFunctions = executableFunctions == null ? ReadOnlyList.empty() : executableFunctions;
reservedMetadata = reservedMetadata == null ? IRReservedMetadata.empty() : reservedMetadata; reservedMetadata = reservedMetadata == null ? IRReservedMetadata.empty() : reservedMetadata;
modulePool = modulePool == null ? ReadOnlyList.empty() : modulePool;
callableSignatures = callableSignatures == null ? ReadOnlyList.empty() : callableSignatures; callableSignatures = callableSignatures == null ? ReadOnlyList.empty() : callableSignatures;
intrinsicPool = intrinsicPool == null ? ReadOnlyList.empty() : intrinsicPool; intrinsicPool = intrinsicPool == null ? ReadOnlyList.empty() : intrinsicPool;
} }
@ -26,17 +29,55 @@ public record IRBackendFile(
public IRBackendFile( public IRBackendFile(
final FileId fileId, final FileId fileId,
final ReadOnlyList<IRFunction> functions) { final ReadOnlyList<IRFunction> functions) {
this(fileId, functions, ReadOnlyList.empty(), IRReservedMetadata.empty(), ReadOnlyList.empty(), ReadOnlyList.empty()); this(
fileId,
functions,
ReadOnlyList.empty(),
IRReservedMetadata.empty(),
ReadOnlyList.empty(),
ReadOnlyList.empty(),
ReadOnlyList.empty());
} }
public static IRBackendFile empty(final FileId fileId) { public static IRBackendFile empty(final FileId fileId) {
return new IRBackendFile(fileId, ReadOnlyList.empty(), ReadOnlyList.empty(), IRReservedMetadata.empty(), ReadOnlyList.empty(), ReadOnlyList.empty()); return new IRBackendFile(
fileId,
ReadOnlyList.empty(),
ReadOnlyList.empty(),
IRReservedMetadata.empty(),
ReadOnlyList.empty(),
ReadOnlyList.empty(),
ReadOnlyList.empty());
} }
public IRBackendFile( public IRBackendFile(
final FileId fileId, final FileId fileId,
final ReadOnlyList<IRFunction> functions, final ReadOnlyList<IRFunction> functions,
final IRReservedMetadata reservedMetadata) { final IRReservedMetadata reservedMetadata) {
this(fileId, functions, ReadOnlyList.empty(), reservedMetadata, ReadOnlyList.empty(), ReadOnlyList.empty()); this(
fileId,
functions,
ReadOnlyList.empty(),
reservedMetadata,
ReadOnlyList.empty(),
ReadOnlyList.empty(),
ReadOnlyList.empty());
}
public IRBackendFile(
final FileId fileId,
final ReadOnlyList<IRFunction> functions,
final ReadOnlyList<IRBackendExecutableFunction> executableFunctions,
final IRReservedMetadata reservedMetadata,
final ReadOnlyList<CallableSignatureRef> callableSignatures,
final ReadOnlyList<IntrinsicReference> intrinsicPool) {
this(
fileId,
functions,
executableFunctions,
reservedMetadata,
ReadOnlyList.empty(),
callableSignatures,
intrinsicPool);
} }
} }

View File

@ -5,8 +5,10 @@ import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId; import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId; import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.CallableSignatureRef; import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.IntrinsicReference; import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -300,4 +302,76 @@ class IRBackendExecutableContractTest {
assertEquals(21, emittedInstructionSpan.getStart()); assertEquals(21, emittedInstructionSpan.getStart());
assertEquals(34, emittedInstructionSpan.getEnd()); assertEquals(34, emittedInstructionSpan.getEnd());
} }
@Test
void aggregatorMustReindexModulesIntoGlobalDensePool() {
final var fileA = new IRBackendFile(
new FileId(1),
ReadOnlyList.empty(),
ReadOnlyList.from(new IRBackendExecutableFunction(
new FileId(1),
new ModuleId(0),
"app:mod/a",
"entry",
new CallableId(0),
0,
5,
0,
0,
0,
1,
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.RET,
"",
"",
null,
null,
Span.none())),
Span.none())),
IRReservedMetadata.empty(),
ReadOnlyList.from(new ModuleReference("app", ReadOnlyList.from("mod", "a"))),
ReadOnlyList.from(new CallableSignatureRef(new ModuleId(0), "app:mod/a", "entry", 0, "() -> unit")),
ReadOnlyList.empty());
final var fileB = new IRBackendFile(
new FileId(2),
ReadOnlyList.empty(),
ReadOnlyList.from(new IRBackendExecutableFunction(
new FileId(2),
new ModuleId(0),
"app:mod/b",
"aux",
new CallableId(0),
6,
10,
0,
0,
0,
1,
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.RET,
"",
"",
null,
null,
Span.none())),
Span.none())),
IRReservedMetadata.empty(),
ReadOnlyList.from(new ModuleReference("app", ReadOnlyList.from("mod", "b"))),
ReadOnlyList.from(new CallableSignatureRef(new ModuleId(0), "app:mod/b", "aux", 0, "() -> unit")),
ReadOnlyList.empty());
final var aggregator = IRBackend.aggregator();
aggregator.merge(fileA);
aggregator.merge(fileB);
final var backend = aggregator.emit();
assertEquals(2, backend.getModulePool().size());
assertEquals("mod", backend.getModulePool().get(0).pathSegments().get(0));
assertEquals("a", backend.getModulePool().get(0).pathSegments().get(1));
assertEquals("b", backend.getModulePool().get(1).pathSegments().get(1));
assertEquals(0, backend.getExecutableFunctions().get(0).moduleId().getIndex());
assertEquals(1, backend.getExecutableFunctions().get(1).moduleId().getIndex());
assertEquals(0, backend.getCallableSignatures().get(0).moduleId().getIndex());
assertEquals(1, backend.getCallableSignatures().get(1).moduleId().getIndex());
}
} }