Bytecode for loop over typed range params
This commit is contained in:
parent
2311cfc224
commit
37a8831fd7
@ -126,6 +126,18 @@ class Compiler(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isRangeType(type: TypeDecl): Boolean {
|
||||||
|
val name = when (type) {
|
||||||
|
is TypeDecl.Simple -> type.name
|
||||||
|
is TypeDecl.Generic -> type.name
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
return name == "Range" ||
|
||||||
|
name == "IntRange" ||
|
||||||
|
name.endsWith(".Range") ||
|
||||||
|
name.endsWith(".IntRange")
|
||||||
|
}
|
||||||
|
|
||||||
var packageName: String? = null
|
var packageName: String? = null
|
||||||
|
|
||||||
class Settings(
|
class Settings(
|
||||||
@ -371,6 +383,9 @@ class Compiler(
|
|||||||
private var lastLabel: String? = null
|
private var lastLabel: String? = null
|
||||||
private val useBytecodeStatements: Boolean = true
|
private val useBytecodeStatements: Boolean = true
|
||||||
private val returnLabelStack = ArrayDeque<Set<String>>()
|
private val returnLabelStack = ArrayDeque<Set<String>>()
|
||||||
|
private val rangeParamNamesStack = mutableListOf<Set<String>>()
|
||||||
|
private val currentRangeParamNames: Set<String>
|
||||||
|
get() = rangeParamNamesStack.lastOrNull() ?: emptySet()
|
||||||
|
|
||||||
private fun wrapBytecode(stmt: Statement): Statement {
|
private fun wrapBytecode(stmt: Statement): Statement {
|
||||||
if (!useBytecodeStatements) return stmt
|
if (!useBytecodeStatements) return stmt
|
||||||
@ -380,7 +395,8 @@ class Compiler(
|
|||||||
stmt,
|
stmt,
|
||||||
"stmt@${stmt.pos}",
|
"stmt@${stmt.pos}",
|
||||||
allowLocalSlots = allowLocals,
|
allowLocalSlots = allowLocals,
|
||||||
returnLabels = returnLabels
|
returnLabels = returnLabels,
|
||||||
|
rangeLocalNames = currentRangeParamNames
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +407,8 @@ class Compiler(
|
|||||||
stmt,
|
stmt,
|
||||||
"fn@$name",
|
"fn@$name",
|
||||||
allowLocalSlots = true,
|
allowLocalSlots = true,
|
||||||
returnLabels = returnLabels
|
returnLabels = returnLabels,
|
||||||
|
rangeLocalNames = currentRangeParamNames
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3041,11 +3058,16 @@ class Compiler(
|
|||||||
val paramNamesList = argsDeclaration.params.map { it.name }
|
val paramNamesList = argsDeclaration.params.map { it.name }
|
||||||
val paramNames: Set<String> = paramNamesList.toSet()
|
val paramNames: Set<String> = paramNamesList.toSet()
|
||||||
val paramSlotPlan = buildParamSlotPlan(paramNamesList)
|
val paramSlotPlan = buildParamSlotPlan(paramNamesList)
|
||||||
|
val rangeParamNames = argsDeclaration.params
|
||||||
|
.filter { isRangeType(it.type) }
|
||||||
|
.map { it.name }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
// Parse function body while tracking declared locals to compute precise capacity hints
|
// Parse function body while tracking declared locals to compute precise capacity hints
|
||||||
currentLocalDeclCount
|
currentLocalDeclCount
|
||||||
localDeclCountStack.add(0)
|
localDeclCountStack.add(0)
|
||||||
slotPlanStack.add(paramSlotPlan)
|
slotPlanStack.add(paramSlotPlan)
|
||||||
|
rangeParamNamesStack.add(rangeParamNames)
|
||||||
val parsedFnStatements = try {
|
val parsedFnStatements = try {
|
||||||
val returnLabels = buildSet {
|
val returnLabels = buildSet {
|
||||||
add(name)
|
add(name)
|
||||||
@ -3083,6 +3105,7 @@ class Compiler(
|
|||||||
returnLabelStack.removeLast()
|
returnLabelStack.removeLast()
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
rangeParamNamesStack.removeLast()
|
||||||
slotPlanStack.removeLast()
|
slotPlanStack.removeLast()
|
||||||
}
|
}
|
||||||
val fnStatements = parsedFnStatements?.let {
|
val fnStatements = parsedFnStatements?.let {
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import net.sergeych.lyng.obj.*
|
|||||||
class BytecodeCompiler(
|
class BytecodeCompiler(
|
||||||
private val allowLocalSlots: Boolean = true,
|
private val allowLocalSlots: Boolean = true,
|
||||||
private val returnLabels: Set<String> = emptySet(),
|
private val returnLabels: Set<String> = emptySet(),
|
||||||
|
private val rangeLocalNames: Set<String> = emptySet(),
|
||||||
) {
|
) {
|
||||||
private var builder = CmdBuilder()
|
private var builder = CmdBuilder()
|
||||||
private var nextSlot = 0
|
private var nextSlot = 0
|
||||||
@ -48,6 +49,7 @@ class BytecodeCompiler(
|
|||||||
private var localSlotMutables = BooleanArray(0)
|
private var localSlotMutables = BooleanArray(0)
|
||||||
private var localSlotDepths = IntArray(0)
|
private var localSlotDepths = IntArray(0)
|
||||||
private val declaredLocalKeys = LinkedHashSet<ScopeSlotKey>()
|
private val declaredLocalKeys = LinkedHashSet<ScopeSlotKey>()
|
||||||
|
private val localRangeRefs = LinkedHashMap<ScopeSlotKey, RangeRef>()
|
||||||
private val slotTypes = mutableMapOf<Int, SlotType>()
|
private val slotTypes = mutableMapOf<Int, SlotType>()
|
||||||
private val intLoopVarNames = LinkedHashSet<String>()
|
private val intLoopVarNames = LinkedHashSet<String>()
|
||||||
private val loopStack = ArrayDeque<LoopContext>()
|
private val loopStack = ArrayDeque<LoopContext>()
|
||||||
@ -1672,8 +1674,12 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
private fun emitForIn(stmt: net.sergeych.lyng.ForInStatement, wantResult: Boolean): Int? {
|
private fun emitForIn(stmt: net.sergeych.lyng.ForInStatement, wantResult: Boolean): Int? {
|
||||||
val range = stmt.constRange
|
val range = stmt.constRange
|
||||||
val rangeRef = if (range == null) extractRangeRef(stmt.source) else null
|
var rangeRef = if (range == null) extractRangeRef(stmt.source) else null
|
||||||
if (range == null && rangeRef == null) return null
|
if (range == null && rangeRef == null) {
|
||||||
|
rangeRef = extractRangeFromLocal(stmt.source)
|
||||||
|
}
|
||||||
|
val typedRangeLocal = if (range == null && rangeRef == null) extractTypedRangeLocal(stmt.source) else null
|
||||||
|
if (range == null && rangeRef == null && typedRangeLocal == null) return null
|
||||||
val loopLocalIndex = localSlotIndexByName[stmt.loopVarName] ?: return null
|
val loopLocalIndex = localSlotIndexByName[stmt.loopVarName] ?: return null
|
||||||
val loopSlotId = scopeSlotCount + loopLocalIndex
|
val loopSlotId = scopeSlotCount + loopLocalIndex
|
||||||
|
|
||||||
@ -1685,7 +1691,8 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.CONST_INT, startId, iSlot)
|
builder.emit(Opcode.CONST_INT, startId, iSlot)
|
||||||
builder.emit(Opcode.CONST_INT, endId, endSlot)
|
builder.emit(Opcode.CONST_INT, endId, endSlot)
|
||||||
} else {
|
} else {
|
||||||
val left = rangeRef?.left ?: return null
|
if (rangeRef != null) {
|
||||||
|
val left = rangeRef.left ?: return null
|
||||||
val right = rangeRef.right ?: return null
|
val right = rangeRef.right ?: return null
|
||||||
val startValue = compileRef(left) ?: return null
|
val startValue = compileRef(left) ?: return null
|
||||||
val endValue = compileRef(right) ?: return null
|
val endValue = compileRef(right) ?: return null
|
||||||
@ -1695,6 +1702,73 @@ class BytecodeCompiler(
|
|||||||
if (rangeRef.isEndInclusive) {
|
if (rangeRef.isEndInclusive) {
|
||||||
builder.emit(Opcode.INC_INT, endSlot)
|
builder.emit(Opcode.INC_INT, endSlot)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
val rangeLocal = typedRangeLocal ?: return null
|
||||||
|
val rangeValue = compileRef(rangeLocal) ?: return null
|
||||||
|
val rangeObj = ensureObjSlot(rangeValue)
|
||||||
|
val okSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.RANGE_INT_BOUNDS, rangeObj.slot, iSlot, endSlot, okSlot)
|
||||||
|
val fallbackLabel = builder.label()
|
||||||
|
builder.emit(
|
||||||
|
Opcode.JMP_IF_FALSE,
|
||||||
|
listOf(CmdBuilder.Operand.IntVal(okSlot), CmdBuilder.Operand.LabelRef(fallbackLabel))
|
||||||
|
)
|
||||||
|
val breakFlagSlot = allocSlot()
|
||||||
|
val falseId = builder.addConst(BytecodeConst.Bool(false))
|
||||||
|
builder.emit(Opcode.CONST_BOOL, falseId, breakFlagSlot)
|
||||||
|
|
||||||
|
val resultSlot = allocSlot()
|
||||||
|
val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||||
|
builder.emit(Opcode.CONST_OBJ, voidId, resultSlot)
|
||||||
|
|
||||||
|
val loopLabel = builder.label()
|
||||||
|
val continueLabel = builder.label()
|
||||||
|
val endLabel = builder.label()
|
||||||
|
val doneLabel = builder.label()
|
||||||
|
builder.mark(loopLabel)
|
||||||
|
val cmpSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.CMP_GTE_INT, iSlot, endSlot, cmpSlot)
|
||||||
|
builder.emit(
|
||||||
|
Opcode.JMP_IF_TRUE,
|
||||||
|
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||||
|
)
|
||||||
|
builder.emit(Opcode.MOVE_INT, iSlot, loopSlotId)
|
||||||
|
updateSlotType(loopSlotId, SlotType.INT)
|
||||||
|
updateSlotTypeByName(stmt.loopVarName, SlotType.INT)
|
||||||
|
loopStack.addLast(
|
||||||
|
LoopContext(stmt.label, endLabel, continueLabel, breakFlagSlot, if (wantResult) resultSlot else null)
|
||||||
|
)
|
||||||
|
val bodyValue = compileLoopBody(stmt.body, wantResult) ?: return null
|
||||||
|
loopStack.removeLast()
|
||||||
|
if (wantResult) {
|
||||||
|
val bodyObj = ensureObjSlot(bodyValue)
|
||||||
|
builder.emit(Opcode.MOVE_OBJ, bodyObj.slot, resultSlot)
|
||||||
|
}
|
||||||
|
builder.mark(continueLabel)
|
||||||
|
builder.emit(Opcode.INC_INT, iSlot)
|
||||||
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(loopLabel)))
|
||||||
|
|
||||||
|
builder.mark(endLabel)
|
||||||
|
if (stmt.elseStatement != null) {
|
||||||
|
val afterElse = builder.label()
|
||||||
|
builder.emit(
|
||||||
|
Opcode.JMP_IF_TRUE,
|
||||||
|
listOf(CmdBuilder.Operand.IntVal(breakFlagSlot), CmdBuilder.Operand.LabelRef(afterElse))
|
||||||
|
)
|
||||||
|
val elseValue = compileStatementValueOrFallback(stmt.elseStatement, wantResult) ?: return null
|
||||||
|
if (wantResult) {
|
||||||
|
val elseObj = ensureObjSlot(elseValue)
|
||||||
|
builder.emit(Opcode.MOVE_OBJ, elseObj.slot, resultSlot)
|
||||||
|
}
|
||||||
|
builder.mark(afterElse)
|
||||||
|
}
|
||||||
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(doneLabel)))
|
||||||
|
builder.mark(fallbackLabel)
|
||||||
|
val fallbackId = builder.addFallback(stmt)
|
||||||
|
builder.emit(Opcode.EVAL_FALLBACK, fallbackId, resultSlot)
|
||||||
|
builder.mark(doneLabel)
|
||||||
|
return resultSlot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val breakFlagSlot = allocSlot()
|
val breakFlagSlot = allocSlot()
|
||||||
@ -2105,6 +2179,7 @@ class BytecodeCompiler(
|
|||||||
localSlotMutables = BooleanArray(0)
|
localSlotMutables = BooleanArray(0)
|
||||||
localSlotDepths = IntArray(0)
|
localSlotDepths = IntArray(0)
|
||||||
declaredLocalKeys.clear()
|
declaredLocalKeys.clear()
|
||||||
|
localRangeRefs.clear()
|
||||||
intLoopVarNames.clear()
|
intLoopVarNames.clear()
|
||||||
addrSlotByScopeSlot.clear()
|
addrSlotByScopeSlot.clear()
|
||||||
loopStack.clear()
|
loopStack.clear()
|
||||||
@ -2168,6 +2243,11 @@ class BytecodeCompiler(
|
|||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(stmt.name, stmt.isMutable, slotDepth)
|
localSlotInfoMap[key] = LocalSlotInfo(stmt.name, stmt.isMutable, slotDepth)
|
||||||
}
|
}
|
||||||
|
if (!stmt.isMutable) {
|
||||||
|
extractDeclaredRange(stmt.initializer)?.let { range ->
|
||||||
|
localRangeRefs[key] = range
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stmt.initializer?.let { collectScopeSlots(it) }
|
stmt.initializer?.let { collectScopeSlots(it) }
|
||||||
}
|
}
|
||||||
@ -2527,6 +2607,30 @@ class BytecodeCompiler(
|
|||||||
return expr.ref as? RangeRef
|
return expr.ref as? RangeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extractDeclaredRange(stmt: Statement?): RangeRef? {
|
||||||
|
if (stmt == null) return null
|
||||||
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
|
val expr = target as? ExpressionStatement ?: return null
|
||||||
|
return expr.ref as? RangeRef
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractRangeFromLocal(source: Statement): RangeRef? {
|
||||||
|
val target = if (source is BytecodeStatement) source.original else source
|
||||||
|
val expr = target as? ExpressionStatement ?: return null
|
||||||
|
val localRef = expr.ref as? LocalSlotRef ?: return null
|
||||||
|
val key = ScopeSlotKey(refScopeDepth(localRef), refSlot(localRef))
|
||||||
|
return localRangeRefs[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractTypedRangeLocal(source: Statement): LocalSlotRef? {
|
||||||
|
if (rangeLocalNames.isEmpty()) return null
|
||||||
|
val target = if (source is BytecodeStatement) source.original else source
|
||||||
|
val expr = target as? ExpressionStatement ?: return null
|
||||||
|
val localRef = expr.ref as? LocalSlotRef ?: return null
|
||||||
|
if (localRef.isDelegated) return null
|
||||||
|
return if (rangeLocalNames.contains(localRef.name)) localRef else null
|
||||||
|
}
|
||||||
|
|
||||||
private fun effectiveLocalDepth(depth: Int): Int {
|
private fun effectiveLocalDepth(depth: Int): Int {
|
||||||
if (depth == 0 || virtualScopeDepths.isEmpty()) return depth
|
if (depth == 0 || virtualScopeDepths.isEmpty()) return depth
|
||||||
var virtualCount = 0
|
var virtualCount = 0
|
||||||
|
|||||||
@ -40,12 +40,17 @@ class BytecodeStatement private constructor(
|
|||||||
nameHint: String,
|
nameHint: String,
|
||||||
allowLocalSlots: Boolean,
|
allowLocalSlots: Boolean,
|
||||||
returnLabels: Set<String> = emptySet(),
|
returnLabels: Set<String> = emptySet(),
|
||||||
|
rangeLocalNames: Set<String> = emptySet(),
|
||||||
): Statement {
|
): Statement {
|
||||||
if (statement is BytecodeStatement) return statement
|
if (statement is BytecodeStatement) return statement
|
||||||
val hasUnsupported = containsUnsupportedStatement(statement)
|
val hasUnsupported = containsUnsupportedStatement(statement)
|
||||||
if (hasUnsupported) return unwrapDeep(statement)
|
if (hasUnsupported) return unwrapDeep(statement)
|
||||||
val safeLocals = allowLocalSlots
|
val safeLocals = allowLocalSlots
|
||||||
val compiler = BytecodeCompiler(allowLocalSlots = safeLocals, returnLabels = returnLabels)
|
val compiler = BytecodeCompiler(
|
||||||
|
allowLocalSlots = safeLocals,
|
||||||
|
returnLabels = returnLabels,
|
||||||
|
rangeLocalNames = rangeLocalNames
|
||||||
|
)
|
||||||
val compiled = compiler.compileStatement(nameHint, statement)
|
val compiled = compiler.compileStatement(nameHint, statement)
|
||||||
val fn = compiled ?: run {
|
val fn = compiled ?: run {
|
||||||
val builder = CmdBuilder()
|
val builder = CmdBuilder()
|
||||||
@ -78,11 +83,15 @@ class BytecodeStatement private constructor(
|
|||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
val rangeSource = target.source
|
val rangeSource = target.source
|
||||||
val rangeRef = (rangeSource as? net.sergeych.lyng.ExpressionStatement)?.ref as? RangeRef
|
val rangeRef = (rangeSource as? net.sergeych.lyng.ExpressionStatement)?.ref as? RangeRef
|
||||||
val hasRange = target.constRange != null || rangeRef != null
|
val sourceRef = (rangeSource as? net.sergeych.lyng.ExpressionStatement)?.ref
|
||||||
!hasRange ||
|
val hasRange = target.constRange != null ||
|
||||||
|
rangeRef != null ||
|
||||||
|
(sourceRef is net.sergeych.lyng.obj.LocalSlotRef)
|
||||||
|
val unsupported = !hasRange ||
|
||||||
containsUnsupportedStatement(target.source) ||
|
containsUnsupportedStatement(target.source) ||
|
||||||
containsUnsupportedStatement(target.body) ||
|
containsUnsupportedStatement(target.body) ||
|
||||||
(target.elseStatement?.let { containsUnsupportedStatement(it) } ?: false)
|
(target.elseStatement?.let { containsUnsupportedStatement(it) } ?: false)
|
||||||
|
unsupported
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.WhileStatement -> {
|
is net.sergeych.lyng.WhileStatement -> {
|
||||||
containsUnsupportedStatement(target.condition) ||
|
containsUnsupportedStatement(target.condition) ||
|
||||||
|
|||||||
@ -122,6 +122,8 @@ class CmdBuilder {
|
|||||||
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
||||||
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
|
Opcode.RANGE_INT_BOUNDS ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.RET_LABEL, Opcode.THROW ->
|
Opcode.RET_LABEL, Opcode.THROW ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.RESOLVE_SCOPE_SLOT ->
|
Opcode.RESOLVE_SCOPE_SLOT ->
|
||||||
@ -209,6 +211,7 @@ class CmdBuilder {
|
|||||||
Opcode.CONST_BOOL -> CmdConstBool(operands[0], operands[1])
|
Opcode.CONST_BOOL -> CmdConstBool(operands[0], operands[1])
|
||||||
Opcode.CONST_NULL -> CmdConstNull(operands[0])
|
Opcode.CONST_NULL -> CmdConstNull(operands[0])
|
||||||
Opcode.BOX_OBJ -> CmdBoxObj(operands[0], operands[1])
|
Opcode.BOX_OBJ -> CmdBoxObj(operands[0], operands[1])
|
||||||
|
Opcode.RANGE_INT_BOUNDS -> CmdRangeIntBounds(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.RET_LABEL -> CmdRetLabel(operands[0], operands[1])
|
Opcode.RET_LABEL -> CmdRetLabel(operands[0], operands[1])
|
||||||
Opcode.THROW -> CmdThrow(operands[0], operands[1])
|
Opcode.THROW -> CmdThrow(operands[0], operands[1])
|
||||||
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
|
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
|
||||||
|
|||||||
@ -68,6 +68,7 @@ object CmdDisassembler {
|
|||||||
is CmdConstBool -> Opcode.CONST_BOOL to intArrayOf(cmd.constId, cmd.dst)
|
is CmdConstBool -> Opcode.CONST_BOOL to intArrayOf(cmd.constId, cmd.dst)
|
||||||
is CmdConstNull -> Opcode.CONST_NULL to intArrayOf(cmd.dst)
|
is CmdConstNull -> Opcode.CONST_NULL to intArrayOf(cmd.dst)
|
||||||
is CmdBoxObj -> Opcode.BOX_OBJ to intArrayOf(cmd.src, cmd.dst)
|
is CmdBoxObj -> Opcode.BOX_OBJ to intArrayOf(cmd.src, cmd.dst)
|
||||||
|
is CmdRangeIntBounds -> Opcode.RANGE_INT_BOUNDS to intArrayOf(cmd.src, cmd.startSlot, cmd.endSlot, cmd.okSlot)
|
||||||
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
|
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
|
||||||
is CmdLoadObjAddr -> Opcode.LOAD_OBJ_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
is CmdLoadObjAddr -> Opcode.LOAD_OBJ_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
||||||
is CmdStoreObjAddr -> Opcode.STORE_OBJ_ADDR to intArrayOf(cmd.src, cmd.addrSlot)
|
is CmdStoreObjAddr -> Opcode.STORE_OBJ_ADDR to intArrayOf(cmd.src, cmd.addrSlot)
|
||||||
@ -196,6 +197,8 @@ object CmdDisassembler {
|
|||||||
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
||||||
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
|
Opcode.RANGE_INT_BOUNDS ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.RET_LABEL, Opcode.THROW ->
|
Opcode.RET_LABEL, Opcode.THROW ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.RESOLVE_SCOPE_SLOT ->
|
Opcode.RESOLVE_SCOPE_SLOT ->
|
||||||
|
|||||||
@ -154,6 +154,28 @@ class CmdBoxObj(internal val src: Int, internal val dst: Int) : Cmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CmdRangeIntBounds(
|
||||||
|
internal val src: Int,
|
||||||
|
internal val startSlot: Int,
|
||||||
|
internal val endSlot: Int,
|
||||||
|
internal val okSlot: Int,
|
||||||
|
) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val obj = frame.slotToObj(src)
|
||||||
|
val range = obj as? ObjRange
|
||||||
|
if (range == null || !range.isIntRange) {
|
||||||
|
frame.setBool(okSlot, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val start = (range.start as ObjInt).value
|
||||||
|
val end = (range.end as ObjInt).value
|
||||||
|
frame.setInt(startSlot, start)
|
||||||
|
frame.setInt(endSlot, if (range.isEndInclusive) end + 1 else end)
|
||||||
|
frame.setBool(okSlot, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CmdResolveScopeSlot(internal val scopeSlot: Int, internal val addrSlot: Int) : Cmd() {
|
class CmdResolveScopeSlot(internal val scopeSlot: Int, internal val addrSlot: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
frame.resolveScopeSlotAddr(scopeSlot, addrSlot)
|
frame.resolveScopeSlotAddr(scopeSlot, addrSlot)
|
||||||
|
|||||||
@ -28,6 +28,7 @@ enum class Opcode(val code: Int) {
|
|||||||
CONST_BOOL(0x08),
|
CONST_BOOL(0x08),
|
||||||
CONST_NULL(0x09),
|
CONST_NULL(0x09),
|
||||||
BOX_OBJ(0x0A),
|
BOX_OBJ(0x0A),
|
||||||
|
RANGE_INT_BOUNDS(0x0B),
|
||||||
|
|
||||||
INT_TO_REAL(0x10),
|
INT_TO_REAL(0x10),
|
||||||
REAL_TO_INT(0x11),
|
REAL_TO_INT(0x11),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user