implements PR-O1.2
This commit is contained in:
parent
b5c372efb2
commit
9e3d9ccb93
@ -23,7 +23,22 @@ public record IRBackendExecutableFunction(
|
||||
fileId = Objects.requireNonNull(fileId, "fileId");
|
||||
moduleKey = moduleKey == null ? "" : moduleKey;
|
||||
callableName = Objects.requireNonNull(callableName, "callableName");
|
||||
if (callableName.isBlank()) {
|
||||
throw new IllegalArgumentException("callableName must not be blank");
|
||||
}
|
||||
if (sourceStart < 0 || sourceEnd < 0 || sourceEnd < sourceStart) {
|
||||
throw new IllegalArgumentException("invalid source span bounds");
|
||||
}
|
||||
if (paramSlots < 0 || localSlots < 0 || returnSlots < 0 || maxStackSlots < 0) {
|
||||
throw new IllegalArgumentException("slots must be non-negative");
|
||||
}
|
||||
if (maxStackSlots < returnSlots) {
|
||||
throw new IllegalArgumentException("maxStackSlots must be >= returnSlots");
|
||||
}
|
||||
instructions = instructions == null ? ReadOnlyList.empty() : instructions;
|
||||
for (final var instruction : instructions) {
|
||||
Objects.requireNonNull(instruction, "instruction");
|
||||
}
|
||||
span = span == null ? Span.none() : span;
|
||||
}
|
||||
|
||||
@ -33,29 +48,62 @@ public record IRBackendExecutableFunction(
|
||||
String calleeCallableName,
|
||||
HostCallMetadata hostCall,
|
||||
IntrinsicCallMetadata intrinsicCall,
|
||||
Integer expectedArgSlots,
|
||||
Integer expectedRetSlots,
|
||||
Span span) {
|
||||
public Instruction(
|
||||
final InstructionKind kind,
|
||||
final String calleeModuleKey,
|
||||
final String calleeCallableName,
|
||||
final HostCallMetadata hostCall,
|
||||
final IntrinsicCallMetadata intrinsicCall,
|
||||
final Span span) {
|
||||
this(kind, calleeModuleKey, calleeCallableName, hostCall, intrinsicCall, null, null, span);
|
||||
}
|
||||
|
||||
public Instruction {
|
||||
Objects.requireNonNull(kind, "kind");
|
||||
span = span == null ? Span.none() : span;
|
||||
calleeModuleKey = calleeModuleKey == null ? "" : calleeModuleKey;
|
||||
calleeCallableName = calleeCallableName == null ? "" : calleeCallableName;
|
||||
if (expectedArgSlots != null && expectedArgSlots < 0) {
|
||||
throw new IllegalArgumentException("expectedArgSlots must be non-negative");
|
||||
}
|
||||
if (expectedRetSlots != null && expectedRetSlots < 0) {
|
||||
throw new IllegalArgumentException("expectedRetSlots must be non-negative");
|
||||
}
|
||||
switch (kind) {
|
||||
case CALL_FUNC -> {
|
||||
if (calleeCallableName.isBlank()) {
|
||||
throw new IllegalArgumentException("CALL_FUNC requires calleeCallableName");
|
||||
}
|
||||
if (hostCall != null || intrinsicCall != null) {
|
||||
throw new IllegalArgumentException("CALL_FUNC must not carry host or intrinsic metadata");
|
||||
}
|
||||
}
|
||||
case CALL_HOST -> {
|
||||
if (hostCall == null) {
|
||||
throw new IllegalArgumentException("CALL_HOST requires hostCall metadata");
|
||||
}
|
||||
if (intrinsicCall != null) {
|
||||
throw new IllegalArgumentException("CALL_HOST must not carry intrinsic metadata");
|
||||
}
|
||||
}
|
||||
case CALL_INTRINSIC -> {
|
||||
if (intrinsicCall == null) {
|
||||
throw new IllegalArgumentException("CALL_INTRINSIC requires intrinsic metadata");
|
||||
}
|
||||
if (hostCall != null) {
|
||||
throw new IllegalArgumentException("CALL_INTRINSIC must not carry host metadata");
|
||||
}
|
||||
}
|
||||
case HALT, RET -> {
|
||||
if (!calleeCallableName.isBlank() || hostCall != null || intrinsicCall != null) {
|
||||
throw new IllegalArgumentException(kind + " must not carry callsite metadata");
|
||||
}
|
||||
if (expectedArgSlots != null || expectedRetSlots != null) {
|
||||
throw new IllegalArgumentException(kind + " must not carry expected slot metadata");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,6 +126,12 @@ public record IRBackendExecutableFunction(
|
||||
public HostCallMetadata {
|
||||
module = Objects.requireNonNull(module, "module");
|
||||
name = Objects.requireNonNull(name, "name");
|
||||
if (module.isBlank() || name.isBlank()) {
|
||||
throw new IllegalArgumentException("module and name must not be blank");
|
||||
}
|
||||
if (version < 0 || argSlots < 0 || retSlots < 0) {
|
||||
throw new IllegalArgumentException("host metadata values must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +141,12 @@ public record IRBackendExecutableFunction(
|
||||
int intrinsicId) {
|
||||
public IntrinsicCallMetadata {
|
||||
canonicalName = Objects.requireNonNull(canonicalName, "canonicalName");
|
||||
if (canonicalName.isBlank()) {
|
||||
throw new IllegalArgumentException("canonicalName must not be blank");
|
||||
}
|
||||
if (canonicalVersion < 0) {
|
||||
throw new IllegalArgumentException("canonicalVersion must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class IRBackendExecutableContractTest {
|
||||
|
||||
@ -30,6 +31,54 @@ class IRBackendExecutableContractTest {
|
||||
assertEquals(IRBackendExecutableFunction.InstructionKind.CALL_FUNC, callFunc.kind());
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionContractMustRejectInvalidSlotAndSpanBounds() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
"app",
|
||||
"main",
|
||||
10,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
ReadOnlyList.empty(),
|
||||
Span.none()));
|
||||
|
||||
final var thrown = assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction(
|
||||
new FileId(1),
|
||||
"app",
|
||||
"main",
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
ReadOnlyList.empty(),
|
||||
Span.none()));
|
||||
assertTrue(thrown.getMessage().contains("maxStackSlots"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void instructionContractMustRejectMixedMetadataKinds() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction.Instruction(
|
||||
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
||||
"app/main",
|
||||
"foo",
|
||||
new IRBackendExecutableFunction.HostCallMetadata("gfx", "draw", 1, 0, 0),
|
||||
null,
|
||||
Span.none()));
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction.HostCallMetadata(
|
||||
"gfx",
|
||||
"draw",
|
||||
1,
|
||||
-1,
|
||||
0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aggregatorMustPreserveExecutableFunctionOrderDeterministically() {
|
||||
final var fileA = new IRBackendFile(
|
||||
@ -87,4 +136,3 @@ class IRBackendExecutableContractTest {
|
||||
assertEquals("aux", backend.getExecutableFunctions().get(1).callableName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user