hardens IRGlobal structural metadata for PBS lifecycle lowering
This commit is contained in:
parent
14eaa0e0c0
commit
64762ca227
@ -5,6 +5,8 @@ import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||
import p.studio.compiler.models.IRBackendFile;
|
||||
import p.studio.compiler.models.IRFunction;
|
||||
import p.studio.compiler.models.IRGlobal;
|
||||
import p.studio.compiler.models.IRGlobalOrigin;
|
||||
import p.studio.compiler.models.IRGlobalVisibility;
|
||||
import p.studio.compiler.models.IRReservedMetadata;
|
||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||
import p.studio.compiler.models.IRSyntheticFunction;
|
||||
@ -243,6 +245,7 @@ public final class PbsFrontendCompiler {
|
||||
final ModuleId moduleId,
|
||||
final PbsAst.File ast) {
|
||||
final var globals = new ArrayList<IRGlobal>();
|
||||
var nextSlot = 0;
|
||||
for (final var topDecl : ast.topDecls()) {
|
||||
if (!(topDecl instanceof PbsAst.GlobalDecl globalDecl)) {
|
||||
continue;
|
||||
@ -252,6 +255,16 @@ public final class PbsFrontendCompiler {
|
||||
moduleId,
|
||||
globalDecl.name(),
|
||||
PbsReservedMetadataExtractor.typeSurfaceKey(globalDecl.explicitType()),
|
||||
nextSlot++,
|
||||
IRGlobalVisibility.MODULE,
|
||||
false,
|
||||
p.studio.compiler.models.IRHiddenGlobalKind.NONE,
|
||||
new IRGlobalOrigin(
|
||||
fileId,
|
||||
moduleId,
|
||||
globalDecl.name(),
|
||||
globalDecl.span(),
|
||||
globalDecl.name()),
|
||||
globalDecl.span()));
|
||||
}
|
||||
return ReadOnlyList.wrap(globals);
|
||||
|
||||
@ -5,6 +5,10 @@ import p.studio.compiler.messages.BuildingIssueSink;
|
||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||
import p.studio.compiler.models.IRBackend;
|
||||
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||
import p.studio.compiler.models.IRGlobal;
|
||||
import p.studio.compiler.models.IRGlobalOrigin;
|
||||
import p.studio.compiler.models.IRGlobalVisibility;
|
||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||
import p.studio.compiler.pbs.PbsReservedMetadataExtractor;
|
||||
@ -285,22 +289,34 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||
|
||||
if (globals.stream().noneMatch(global ->
|
||||
moduleIdsMatch(entryPointModuleId, global.moduleId())
|
||||
&& PbsFrontendCompiler.bootGuardGlobalName(entryPointModuleId).equals(global.name()))) {
|
||||
globals.add(new p.studio.compiler.models.IRGlobal(
|
||||
&& global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)) {
|
||||
globals.add(new IRGlobal(
|
||||
frameExecutable.fileId(),
|
||||
entryPointModuleId,
|
||||
PbsFrontendCompiler.bootGuardGlobalName(entryPointModuleId),
|
||||
"bool",
|
||||
0,
|
||||
IRGlobalVisibility.MODULE,
|
||||
true,
|
||||
IRHiddenGlobalKind.BOOT_GUARD,
|
||||
new IRGlobalOrigin(
|
||||
frameExecutable.fileId(),
|
||||
entryPointModuleId,
|
||||
frameAnchorsByModule.getOrDefault(entryPointModuleId, frameExecutable.callableName()),
|
||||
frameExecutable.span(),
|
||||
"BOOT_GUARD"),
|
||||
frameExecutable.span()));
|
||||
}
|
||||
}
|
||||
|
||||
final var normalizedGlobals = normalizeGlobalSlots(globals);
|
||||
|
||||
return IRBackend.builder()
|
||||
.entryPointCallableName(entryPointCallableName)
|
||||
.entryPointModuleId(entryPointModuleId)
|
||||
.functions(baseBackend.getFunctions())
|
||||
.syntheticFunctions(baseBackend.getSyntheticFunctions())
|
||||
.globals(ReadOnlyList.wrap(globals))
|
||||
.globals(ReadOnlyList.wrap(normalizedGlobals))
|
||||
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
||||
.modulePool(baseBackend.getModulePool())
|
||||
.callableSignatures(ReadOnlyList.wrap(callableSignatures))
|
||||
@ -309,6 +325,28 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||
.build();
|
||||
}
|
||||
|
||||
private ArrayList<IRGlobal> normalizeGlobalSlots(final ArrayList<IRGlobal> globals) {
|
||||
final var nextSlotByModule = new LinkedHashMap<ModuleId, Integer>();
|
||||
final var normalized = new ArrayList<IRGlobal>(globals.size());
|
||||
for (final var global : globals) {
|
||||
final var moduleId = normalizeModuleId(global.moduleId());
|
||||
final var slot = nextSlotByModule.getOrDefault(moduleId, 0);
|
||||
nextSlotByModule.put(moduleId, slot + 1);
|
||||
normalized.add(new IRGlobal(
|
||||
global.fileId(),
|
||||
moduleId,
|
||||
global.name(),
|
||||
global.declaredTypeSurface(),
|
||||
slot,
|
||||
global.visibility(),
|
||||
global.isHidden(),
|
||||
global.hiddenKind(),
|
||||
global.origin(),
|
||||
global.span()));
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private IRBackendExecutableFunction resolveExecutable(
|
||||
final ArrayList<IRBackendExecutableFunction> executableFunctions,
|
||||
final ModuleId moduleId,
|
||||
|
||||
@ -2,6 +2,7 @@ package p.studio.compiler.pbs;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import p.studio.compiler.messages.HostAdmissionContext;
|
||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||
import p.studio.compiler.models.SourceKind;
|
||||
import p.studio.compiler.pbs.lexer.LexErrors;
|
||||
@ -12,6 +13,7 @@ import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PbsFrontendCompilerTest {
|
||||
@ -60,6 +62,10 @@ class PbsFrontendCompilerTest {
|
||||
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||
assertEquals(1, fileBackend.globals().size());
|
||||
assertEquals("SCORE", fileBackend.globals().getFirst().name());
|
||||
assertEquals(0, fileBackend.globals().getFirst().slot());
|
||||
assertFalse(fileBackend.globals().getFirst().isHidden());
|
||||
assertEquals(IRHiddenGlobalKind.NONE, fileBackend.globals().getFirst().hiddenKind());
|
||||
assertEquals("SCORE", fileBackend.globals().getFirst().origin().derivedFromUserSymbol());
|
||||
assertEquals(4, fileBackend.syntheticFunctions().size());
|
||||
assertTrue(fileBackend.syntheticFunctions().stream().anyMatch(fn -> fn.kind() == IRSyntheticCallableKind.FILE_INIT_FRAGMENT));
|
||||
assertTrue(fileBackend.syntheticFunctions().stream().anyMatch(fn -> fn.kind() == IRSyntheticCallableKind.MODULE_INIT));
|
||||
|
||||
@ -5,6 +5,7 @@ import org.junit.jupiter.api.io.TempDir;
|
||||
import p.studio.compiler.messages.BuildingIssueSink;
|
||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||
import p.studio.compiler.models.BuildStack;
|
||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
||||
import p.studio.compiler.models.ProjectDescriptor;
|
||||
import p.studio.compiler.models.SourceHandle;
|
||||
import p.studio.compiler.models.SourceKind;
|
||||
@ -362,8 +363,12 @@ class PBSFrontendPhaseServiceTest {
|
||||
|
||||
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||
assertTrue(irBackend.getEntryPointCallableName().startsWith("__pbs.frame_wrapper$m"));
|
||||
assertTrue(irBackend.getGlobals().stream().anyMatch(global ->
|
||||
global.name().startsWith("__pbs.boot_guard$m")));
|
||||
final var bootGuard = irBackend.getGlobals().stream()
|
||||
.filter(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertTrue(bootGuard.isHidden());
|
||||
assertTrue(bootGuard.name().startsWith("__pbs.boot_guard$m"));
|
||||
final var wrapper = irBackend.getExecutableFunctions().stream()
|
||||
.filter(function -> irBackend.getEntryPointCallableName().equals(function.callableName()))
|
||||
.findFirst()
|
||||
@ -439,7 +444,7 @@ class PBSFrontendPhaseServiceTest {
|
||||
assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function ->
|
||||
function.callableName().startsWith("__pbs.project_init$m")));
|
||||
assertTrue(irBackend.getGlobals().stream().anyMatch(global -> "SCORE".equals(global.name())));
|
||||
assertTrue(irBackend.getGlobals().stream().anyMatch(global -> global.name().startsWith("__pbs.boot_guard$m")));
|
||||
assertTrue(irBackend.getGlobals().stream().anyMatch(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -5,6 +5,7 @@ import p.studio.compiler.backend.bytecode.BytecodeModule;
|
||||
import p.studio.compiler.models.IRBackend;
|
||||
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
||||
import p.studio.compiler.source.Span;
|
||||
import p.studio.compiler.source.identifiers.CallableId;
|
||||
import p.studio.compiler.source.identifiers.ModuleId;
|
||||
@ -501,9 +502,9 @@ public class LowerToIRVMService {
|
||||
"synthetic wrapper entrypoint missing: " + publishedWrapper.callableName());
|
||||
}
|
||||
|
||||
final var expectedBootGuardName = bootGuardName(publishedWrapper.moduleId());
|
||||
final var bootGuardPresent = backend.getGlobals().stream()
|
||||
.anyMatch(global -> expectedBootGuardName.equals(global.name())
|
||||
.anyMatch(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD
|
||||
&& global.isHidden()
|
||||
&& sameModuleIdentity(publishedWrapper.moduleId(), global.moduleId()));
|
||||
if (!bootGuardPresent) {
|
||||
throw new IRVMLoweringException(
|
||||
@ -531,11 +532,6 @@ public class LowerToIRVMService {
|
||||
return publishedWrapper;
|
||||
}
|
||||
|
||||
private String bootGuardName(final ModuleId moduleId) {
|
||||
final var normalizedModuleId = moduleId == null ? ModuleId.none() : moduleId;
|
||||
return "__pbs.boot_guard$m" + (normalizedModuleId.isNone() ? -1 : normalizedModuleId.getIndex());
|
||||
}
|
||||
|
||||
private boolean sameModuleIdentity(
|
||||
final ModuleId left,
|
||||
final ModuleId right) {
|
||||
|
||||
@ -4,6 +4,9 @@ import org.junit.jupiter.api.Test;
|
||||
import p.studio.compiler.models.IRBackend;
|
||||
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||
import p.studio.compiler.models.IRGlobal;
|
||||
import p.studio.compiler.models.IRGlobalOrigin;
|
||||
import p.studio.compiler.models.IRGlobalVisibility;
|
||||
import p.studio.compiler.models.IRHiddenGlobalKind;
|
||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||
import p.studio.compiler.models.IRSyntheticFunction;
|
||||
import p.studio.compiler.models.IRSyntheticOrigin;
|
||||
@ -66,12 +69,7 @@ class LowerToIRVMServiceTest {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("__pbs.frame_wrapper$m0")
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.globals(ReadOnlyList.from(new IRGlobal(
|
||||
new FileId(0),
|
||||
new ModuleId(0),
|
||||
"__pbs.boot_guard$m0",
|
||||
"bool",
|
||||
Span.none())))
|
||||
.globals(ReadOnlyList.from(hiddenBootGuard(0)))
|
||||
.syntheticFunctions(ReadOnlyList.from(new IRSyntheticFunction(
|
||||
new ModuleId(0),
|
||||
"__pbs.frame_wrapper$m0",
|
||||
@ -115,12 +113,7 @@ class LowerToIRVMServiceTest {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("__pbs.frame_wrapper$m0")
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.globals(ReadOnlyList.from(new IRGlobal(
|
||||
new FileId(0),
|
||||
new ModuleId(0),
|
||||
"__pbs.boot_guard$m0",
|
||||
"bool",
|
||||
Span.none())))
|
||||
.globals(ReadOnlyList.from(hiddenBootGuard(0)))
|
||||
.syntheticFunctions(ReadOnlyList.from(new IRSyntheticFunction(
|
||||
new ModuleId(0),
|
||||
"__pbs.frame_wrapper$m0",
|
||||
@ -139,12 +132,7 @@ class LowerToIRVMServiceTest {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("frame")
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.globals(ReadOnlyList.from(new IRGlobal(
|
||||
new FileId(0),
|
||||
new ModuleId(0),
|
||||
"__pbs.boot_guard$m0",
|
||||
"bool",
|
||||
Span.none())))
|
||||
.globals(ReadOnlyList.from(hiddenBootGuard(0)))
|
||||
.syntheticFunctions(ReadOnlyList.from(new IRSyntheticFunction(
|
||||
new ModuleId(0),
|
||||
"__pbs.frame_wrapper$m0",
|
||||
@ -187,12 +175,7 @@ class LowerToIRVMServiceTest {
|
||||
final var backend = IRBackend.builder()
|
||||
.entryPointCallableName("__pbs.frame_wrapper$m0")
|
||||
.entryPointModuleId(new ModuleId(0))
|
||||
.globals(ReadOnlyList.from(new IRGlobal(
|
||||
new FileId(0),
|
||||
new ModuleId(0),
|
||||
"__pbs.boot_guard$m0",
|
||||
"bool",
|
||||
Span.none())))
|
||||
.globals(ReadOnlyList.from(userVisibleGlobal("__pbs.boot_guard$m0", 0)))
|
||||
.syntheticFunctions(ReadOnlyList.from(new IRSyntheticFunction(
|
||||
new ModuleId(0),
|
||||
"__pbs.frame_wrapper$m0",
|
||||
@ -419,6 +402,38 @@ class LowerToIRVMServiceTest {
|
||||
assertTrue(thrown.getMessage().contains("qualified entrypoint"));
|
||||
}
|
||||
|
||||
private static IRGlobal hiddenBootGuard(final int moduleId) {
|
||||
final var fileId = new FileId(0);
|
||||
final var ownerModuleId = new ModuleId(moduleId);
|
||||
return new IRGlobal(
|
||||
fileId,
|
||||
ownerModuleId,
|
||||
"__pbs.boot_guard$m" + moduleId,
|
||||
"bool",
|
||||
0,
|
||||
IRGlobalVisibility.MODULE,
|
||||
true,
|
||||
IRHiddenGlobalKind.BOOT_GUARD,
|
||||
new IRGlobalOrigin(fileId, ownerModuleId, "frame", Span.none(), "BOOT_GUARD"),
|
||||
Span.none());
|
||||
}
|
||||
|
||||
private static IRGlobal userVisibleGlobal(final String name, final int moduleId) {
|
||||
final var fileId = new FileId(0);
|
||||
final var ownerModuleId = new ModuleId(moduleId);
|
||||
return new IRGlobal(
|
||||
fileId,
|
||||
ownerModuleId,
|
||||
name,
|
||||
"bool",
|
||||
0,
|
||||
IRGlobalVisibility.MODULE,
|
||||
false,
|
||||
IRHiddenGlobalKind.NONE,
|
||||
new IRGlobalOrigin(fileId, ownerModuleId, name, Span.none(), name),
|
||||
Span.none());
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction fn(
|
||||
final String name,
|
||||
final String moduleKey,
|
||||
|
||||
@ -73,6 +73,16 @@ public class IRBackend {
|
||||
remapModuleId(global.moduleId(), moduleRemap, "global"),
|
||||
global.name(),
|
||||
global.declaredTypeSurface(),
|
||||
global.slot(),
|
||||
global.visibility(),
|
||||
global.isHidden(),
|
||||
global.hiddenKind(),
|
||||
new IRGlobalOrigin(
|
||||
global.origin().derivedFromFile(),
|
||||
remapModuleId(global.origin().derivedFromModule(), moduleRemap, "global origin"),
|
||||
global.origin().derivedFromUserSymbol(),
|
||||
global.origin().primarySpan(),
|
||||
global.origin().fallbackSyntheticLabel()),
|
||||
global.span()));
|
||||
}
|
||||
final var callableRemap = reindexCallables(backendFile.callableSignatures(), moduleRemap);
|
||||
|
||||
@ -11,13 +11,43 @@ public record IRGlobal(
|
||||
ModuleId moduleId,
|
||||
String name,
|
||||
String declaredTypeSurface,
|
||||
int slot,
|
||||
IRGlobalVisibility visibility,
|
||||
boolean isHidden,
|
||||
IRHiddenGlobalKind hiddenKind,
|
||||
IRGlobalOrigin origin,
|
||||
Span span) {
|
||||
public IRGlobal {
|
||||
fileId = Objects.requireNonNull(fileId, "fileId");
|
||||
moduleId = moduleId == null ? ModuleId.none() : moduleId;
|
||||
name = Objects.requireNonNull(name, "name");
|
||||
declaredTypeSurface = declaredTypeSurface == null ? "" : declaredTypeSurface;
|
||||
slot = Math.max(0, slot);
|
||||
visibility = visibility == null ? IRGlobalVisibility.MODULE : visibility;
|
||||
hiddenKind = hiddenKind == null ? IRHiddenGlobalKind.NONE : hiddenKind;
|
||||
isHidden = isHidden || hiddenKind != IRHiddenGlobalKind.NONE;
|
||||
span = span == null ? Span.none() : span;
|
||||
origin = origin == null
|
||||
? new IRGlobalOrigin(fileId, moduleId, name, span, name)
|
||||
: origin;
|
||||
}
|
||||
|
||||
public IRGlobal(
|
||||
final FileId fileId,
|
||||
final ModuleId moduleId,
|
||||
final String name,
|
||||
final String declaredTypeSurface,
|
||||
final Span span) {
|
||||
this(
|
||||
fileId,
|
||||
moduleId,
|
||||
name,
|
||||
declaredTypeSurface,
|
||||
0,
|
||||
IRGlobalVisibility.MODULE,
|
||||
false,
|
||||
IRHiddenGlobalKind.NONE,
|
||||
new IRGlobalOrigin(fileId, moduleId, name, span, name),
|
||||
span);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package p.studio.compiler.models;
|
||||
|
||||
import p.studio.compiler.source.Span;
|
||||
import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.compiler.source.identifiers.ModuleId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record IRGlobalOrigin(
|
||||
FileId derivedFromFile,
|
||||
ModuleId derivedFromModule,
|
||||
String derivedFromUserSymbol,
|
||||
Span primarySpan,
|
||||
String fallbackSyntheticLabel) {
|
||||
public IRGlobalOrigin {
|
||||
derivedFromFile = Objects.requireNonNull(derivedFromFile, "derivedFromFile");
|
||||
derivedFromModule = derivedFromModule == null ? ModuleId.none() : derivedFromModule;
|
||||
derivedFromUserSymbol = derivedFromUserSymbol == null ? "" : derivedFromUserSymbol;
|
||||
primarySpan = primarySpan == null ? Span.none() : primarySpan;
|
||||
fallbackSyntheticLabel = fallbackSyntheticLabel == null ? "" : fallbackSyntheticLabel;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package p.studio.compiler.models;
|
||||
|
||||
public enum IRGlobalVisibility {
|
||||
MODULE,
|
||||
PUBLIC
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package p.studio.compiler.models;
|
||||
|
||||
public enum IRHiddenGlobalKind {
|
||||
NONE,
|
||||
BOOT_GUARD
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user