implements PR-O3.3
This commit is contained in:
parent
0df936e36f
commit
a79a19cd4f
@ -0,0 +1,44 @@
|
|||||||
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public final class IRVMProfileFeatureGate {
|
||||||
|
private final Map<String, Set<IRVMOp>> allowedByProfile;
|
||||||
|
|
||||||
|
public IRVMProfileFeatureGate() {
|
||||||
|
this(Map.of(
|
||||||
|
"core-v1", Set.of(
|
||||||
|
IRVMOp.HALT,
|
||||||
|
IRVMOp.RET,
|
||||||
|
IRVMOp.CALL,
|
||||||
|
IRVMOp.JMP,
|
||||||
|
IRVMOp.JMP_IF_TRUE,
|
||||||
|
IRVMOp.JMP_IF_FALSE,
|
||||||
|
IRVMOp.HOSTCALL,
|
||||||
|
IRVMOp.INTRINSIC,
|
||||||
|
IRVMOp.PUSH_I32),
|
||||||
|
"experimental-v1", Set.of(
|
||||||
|
IRVMOp.HALT,
|
||||||
|
IRVMOp.RET,
|
||||||
|
IRVMOp.CALL,
|
||||||
|
IRVMOp.JMP,
|
||||||
|
IRVMOp.JMP_IF_TRUE,
|
||||||
|
IRVMOp.JMP_IF_FALSE,
|
||||||
|
IRVMOp.HOSTCALL,
|
||||||
|
IRVMOp.INTRINSIC,
|
||||||
|
IRVMOp.PUSH_I32,
|
||||||
|
IRVMOp.INTERNAL_EXT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVMProfileFeatureGate(final Map<String, Set<IRVMOp>> allowedByProfile) {
|
||||||
|
this.allowedByProfile = allowedByProfile == null ? Map.of() : Map.copyOf(allowedByProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowed(
|
||||||
|
final String profile,
|
||||||
|
final IRVMOp op) {
|
||||||
|
final var allowed = allowedByProfile.get(profile == null || profile.isBlank() ? "core-v1" : profile);
|
||||||
|
return allowed != null && allowed.contains(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,5 +9,5 @@ public enum IRVMValidationErrorCode {
|
|||||||
MARSHAL_VERIFY_PRECHECK_INVALID_FUNC_ID,
|
MARSHAL_VERIFY_PRECHECK_INVALID_FUNC_ID,
|
||||||
MARSHAL_VERIFY_PRECHECK_UNTERMINATED_PATH,
|
MARSHAL_VERIFY_PRECHECK_UNTERMINATED_PATH,
|
||||||
MARSHAL_VERIFY_PRECHECK_INTERNAL_OPCODE_RESIDUAL,
|
MARSHAL_VERIFY_PRECHECK_INTERNAL_OPCODE_RESIDUAL,
|
||||||
|
MARSHAL_VERIFY_PRECHECK_OPCODE_NOT_ALLOWED_FOR_PROFILE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,15 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
public class IRVMValidator {
|
public class IRVMValidator {
|
||||||
|
private final IRVMProfileFeatureGate profileFeatureGate;
|
||||||
|
|
||||||
|
public IRVMValidator() {
|
||||||
|
this(new IRVMProfileFeatureGate());
|
||||||
|
}
|
||||||
|
|
||||||
|
IRVMValidator(final IRVMProfileFeatureGate profileFeatureGate) {
|
||||||
|
this.profileFeatureGate = profileFeatureGate;
|
||||||
|
}
|
||||||
|
|
||||||
public void validate(
|
public void validate(
|
||||||
final IRVMModule module,
|
final IRVMModule module,
|
||||||
@ -40,6 +49,13 @@ public class IRVMValidator {
|
|||||||
functionIndex,
|
functionIndex,
|
||||||
pcByIndex[i]);
|
pcByIndex[i]);
|
||||||
}
|
}
|
||||||
|
if (!profileFeatureGate.isAllowed(module.vmProfile(), instr.op())) {
|
||||||
|
throw new IRVMValidationException(
|
||||||
|
IRVMValidationErrorCode.MARSHAL_VERIFY_PRECHECK_OPCODE_NOT_ALLOWED_FOR_PROFILE,
|
||||||
|
"opcode '%s' is not allowed for vm profile '%s'".formatted(instr.op().name(), module.vmProfile()),
|
||||||
|
functionIndex,
|
||||||
|
pcByIndex[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final var worklist = new ArrayDeque<Integer>();
|
final var worklist = new ArrayDeque<Integer>();
|
||||||
@ -222,4 +238,3 @@ public class IRVMValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
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;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
class IRVMValidatorTest {
|
class IRVMValidatorTest {
|
||||||
@ -84,5 +85,41 @@ class IRVMValidatorTest {
|
|||||||
final var thrown = assertThrows(IRVMValidationException.class, () -> validator.validate(module, true));
|
final var thrown = assertThrows(IRVMValidationException.class, () -> validator.validate(module, true));
|
||||||
assertEquals(IRVMValidationErrorCode.MARSHAL_VERIFY_PRECHECK_INTERNAL_OPCODE_RESIDUAL, thrown.code());
|
assertEquals(IRVMValidationErrorCode.MARSHAL_VERIFY_PRECHECK_INTERNAL_OPCODE_RESIDUAL, thrown.code());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validateMustRejectOpcodeOutsideProfileFeatureGate() {
|
||||||
|
final var module = new IRVMModule(
|
||||||
|
"core-v1",
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new IRVMFunction(
|
||||||
|
"main",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new IRVMInstruction(IRVMOp.INTERNAL_EXT, null),
|
||||||
|
new IRVMInstruction(IRVMOp.HALT, null)))));
|
||||||
|
|
||||||
|
final var thrown = assertThrows(IRVMValidationException.class, () -> validator.validate(module, false));
|
||||||
|
assertEquals(IRVMValidationErrorCode.MARSHAL_VERIFY_PRECHECK_OPCODE_NOT_ALLOWED_FOR_PROFILE, thrown.code());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validateMayAllowProfileSpecificOpcodeWhenProfileSupportsIt() {
|
||||||
|
final var module = new IRVMModule(
|
||||||
|
"experimental-v1",
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new IRVMFunction(
|
||||||
|
"main",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new IRVMInstruction(IRVMOp.INTERNAL_EXT, null),
|
||||||
|
new IRVMInstruction(IRVMOp.HALT, null)))));
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> validator.validate(module, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user