From fd2da1efd3405856a4d241ce8a35139df844a5f2 Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 16 Feb 2026 06:16:29 +0300 Subject: [PATCH] VM optimizations --- .../net/sergeych/lyng/ClassDeclStatement.kt | 17 +- .../kotlin/net/sergeych/lyng/Compiler.kt | 14 +- .../lyng/bytecode/BytecodeCompiler.kt | 743 +++++++++- .../lyng/bytecode/BytecodeStatement.kt | 2 + .../net/sergeych/lyng/bytecode/CmdBuilder.kt | 466 +++++- .../sergeych/lyng/bytecode/CmdDisassembler.kt | 233 ++- .../net/sergeych/lyng/bytecode/CmdRuntime.kt | 1308 ++++++++++++++--- .../net/sergeych/lyng/bytecode/Opcode.kt | 33 +- .../kotlin/net/sergeych/lyng/obj/ObjBool.kt | 6 +- .../kotlin/net/sergeych/lyng/obj/ObjClass.kt | 37 +- .../kotlin/net/sergeych/lyng/obj/ObjInt.kt | 3 +- .../kotlin/net/sergeych/lyng/obj/ObjReal.kt | 4 +- .../kotlin/net/sergeych/lyng/obj/ObjString.kt | 3 +- .../kotlin/RepresentativeBenchmarkTest.kt | 79 + .../RepresentativeObjectBenchmarkTest.kt | 163 ++ lynglib/src/commonTest/kotlin/TypesTest.kt | 12 + notes/nested_loop_vm_state.md | 6 + notes/vm_fastpath_plan.md | 49 + 18 files changed, 2847 insertions(+), 331 deletions(-) create mode 100644 lynglib/src/commonTest/kotlin/RepresentativeBenchmarkTest.kt create mode 100644 lynglib/src/commonTest/kotlin/RepresentativeObjectBenchmarkTest.kt create mode 100644 notes/vm_fastpath_plan.md diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassDeclStatement.kt index c64a1a5..659ec14 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassDeclStatement.kt @@ -1,5 +1,5 @@ /* - * Copyright 2026 Sergey S. Chernov + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,17 +12,12 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * */ package net.sergeych.lyng -import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjClass -import net.sergeych.lyng.obj.ObjException -import net.sergeych.lyng.obj.ObjInstance -import net.sergeych.lyng.obj.ObjInstanceClass -import net.sergeych.lyng.obj.ObjNull -import net.sergeych.lyng.obj.ObjRecord +import net.sergeych.lyng.obj.* data class ClassDeclBaseSpec( val name: String, @@ -51,11 +46,16 @@ internal suspend fun executeClassDecl( bodyCaptureRecords: List? = null, bodyCaptureNames: List? = null ): Obj { + fun checkClosedParents(parents: List, pos: Pos) { + val closedParent = parents.firstOrNull { it.isClosed } ?: return + throw ScriptError(pos, "can't inherit from closed class ${closedParent.className}") + } if (spec.isObject) { val parentClasses = spec.baseSpecs.map { baseSpec -> val rec = scope[baseSpec.name] ?: throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}") (rec.value as? ObjClass) ?: throw ScriptError(spec.startPos, "${baseSpec.name} is not a class") } + checkClosedParents(parentClasses, spec.startPos) val newClass = ObjInstanceClass(spec.className, *parentClasses.toTypedArray()) newClass.isAnonymous = spec.isAnonymous @@ -106,6 +106,7 @@ internal suspend fun executeClassDecl( if (rec == null) throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}") throw ScriptError(spec.startPos, "${baseSpec.name} is not a class") } + checkClosedParents(parentClasses, spec.startPos) val constructorCode = object : Statement() { override val pos: Pos = spec.startPos diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 9224634..c230712 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -18,11 +18,7 @@ package net.sergeych.lyng import net.sergeych.lyng.Compiler.Companion.compile -import net.sergeych.lyng.bytecode.BytecodeStatement -import net.sergeych.lyng.bytecode.ForcedLocalSlotInfo -import net.sergeych.lyng.bytecode.CmdListLiteral -import net.sergeych.lyng.bytecode.CmdMakeRange -import net.sergeych.lyng.bytecode.CmdRangeIntBounds +import net.sergeych.lyng.bytecode.* import net.sergeych.lyng.miniast.* import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportManager @@ -1643,6 +1639,7 @@ class Compiler( forcedLocalSlotInfo = forcedLocalInfo, forcedLocalScopeId = forcedLocalScopeId, slotTypeByScopeId = slotTypeByScopeId, + slotTypeDeclByScopeId = slotTypeDeclByScopeId, knownNameObjClass = knownClassMapForBytecode(), knownObjectNames = objectDeclNames, classFieldTypesByName = classFieldTypesByName, @@ -1941,6 +1938,7 @@ class Compiler( scopeSlotNameSet = scopeSlotNameSet, moduleScopeId = moduleScopeId, slotTypeByScopeId = slotTypeByScopeId, + slotTypeDeclByScopeId = slotTypeDeclByScopeId, knownNameObjClass = knownClassMapForBytecode(), knownObjectNames = objectDeclNames, classFieldTypesByName = classFieldTypesByName, @@ -1969,6 +1967,7 @@ class Compiler( scopeSlotNameSet = scopeSlotNameSet, moduleScopeId = moduleScopeId, slotTypeByScopeId = slotTypeByScopeId, + slotTypeDeclByScopeId = slotTypeDeclByScopeId, knownNameObjClass = knownClassMapForBytecode(), knownObjectNames = objectDeclNames, classFieldTypesByName = classFieldTypesByName, @@ -2022,6 +2021,7 @@ class Compiler( globalSlotInfo = globalSlotInfo, globalSlotScopeId = globalSlotScopeId, slotTypeByScopeId = slotTypeByScopeId, + slotTypeDeclByScopeId = slotTypeDeclByScopeId, knownNameObjClass = knownNames, knownObjectNames = objectDeclNames, classFieldTypesByName = classFieldTypesByName, @@ -7580,6 +7580,10 @@ class Compiler( val info = compileClassInfos[name] ?: return null val stub = compileClassStubs.getOrPut(info.name) { val parents = info.baseNames.mapNotNull { resolveClassByName(it) } + val closedParent = parents.firstOrNull { it.isClosed } + if (closedParent != null) { + throw ScriptError(Pos.builtIn, "can't inherit from closed class ${closedParent.className}") + } ObjInstanceClass(info.name, *parents.toTypedArray()) } if (stub is ObjInstanceClass) { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt index 6a6526a..2ac1ea2 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -33,6 +33,7 @@ class BytecodeCompiler( private val globalSlotInfo: Map = emptyMap(), private val globalSlotScopeId: Int? = null, private val slotTypeByScopeId: Map> = emptyMap(), + private val slotTypeDeclByScopeId: Map> = emptyMap(), private val knownNameObjClass: Map = emptyMap(), private val knownObjectNames: Set = emptySet(), private val classFieldTypesByName: Map> = emptyMap(), @@ -51,6 +52,7 @@ class BytecodeCompiler( private var scopeSlotNames = emptyArray() private var scopeSlotIsModule = BooleanArray(0) private var scopeSlotMutables = BooleanArray(0) + private var scopeKeyByIndex = emptyArray() private val scopeSlotMap = LinkedHashMap() private val scopeSlotNameMap = LinkedHashMap() private val scopeSlotMutableMap = LinkedHashMap() @@ -68,11 +70,14 @@ class BytecodeCompiler( private var localSlotMutables = BooleanArray(0) private var localSlotDelegated = BooleanArray(0) private var localSlotCaptures = BooleanArray(0) + private var localSlotKeyByIndex = emptyArray() private val declaredLocalKeys = LinkedHashSet() private val localRangeRefs = LinkedHashMap() private val slotTypes = mutableMapOf() private val slotObjClass = mutableMapOf() + private val stableObjSlots = mutableSetOf() private val nameObjClass = knownNameObjClass.toMutableMap() + private val listElementClassBySlot = mutableMapOf() private val knownClassNames = knownNameObjClass.keys.toSet() private val slotInitClassByKey = mutableMapOf() private val intLoopVarNames = LinkedHashSet() @@ -531,6 +536,9 @@ class BytecodeCompiler( val local = allocSlot() emitLoadFromAddr(addrSlot, local, resolved) updateSlotType(local, resolved) + if (resolved == SlotType.OBJ) { + propagateObjClass(SlotType.OBJ, mapped, local) + } return CompiledValue(local, resolved) } if (mapped < scopeSlotCount && resolved == SlotType.UNKNOWN) { @@ -538,6 +546,7 @@ class BytecodeCompiler( val local = allocSlot() emitLoadFromAddr(addrSlot, local, SlotType.OBJ) updateSlotType(local, SlotType.OBJ) + propagateObjClass(SlotType.OBJ, mapped, local) return CompiledValue(local, SlotType.OBJ) } CompiledValue(mapped, resolved) @@ -589,6 +598,9 @@ class BytecodeCompiler( val local = allocSlot() emitLoadFromAddr(addrSlot, local, resolved) updateSlotType(local, resolved) + if (resolved == SlotType.OBJ) { + propagateObjClass(SlotType.OBJ, slot, local) + } return CompiledValue(local, resolved) } CompiledValue(slot, resolved) @@ -773,6 +785,7 @@ class BytecodeCompiler( is ObjString -> { val id = builder.addConst(BytecodeConst.StringVal(obj.value)) builder.emit(Opcode.CONST_OBJ, id, slot) + slotObjClass[slot] = ObjString.type return CompiledValue(slot, SlotType.OBJ) } ObjNull -> { @@ -870,6 +883,8 @@ class BytecodeCompiler( val count = entries.size val baseSlot = nextSlot val entrySlots = IntArray(count) { allocSlot() } + var elementClass: ObjClass? = null + var elementClassValid = true val spreads = ArrayList(count) for ((index, entry) in entries.withIndex()) { val value = when (entry) { @@ -878,6 +893,20 @@ class BytecodeCompiler( is net.sergeych.lyng.ListEntry.Spread -> compileRefWithFallback(entry.ref, null, Pos.builtIn) } ?: return null + val entryClass = when (entry) { + is net.sergeych.lyng.ListEntry.Element -> { + val constClass = (entry.ref as? ConstRef)?.let { elementClassFromConst(it.constValue) } + constClass ?: elementClassFromValue(value) + } + is net.sergeych.lyng.ListEntry.Spread -> listElementClassBySlot[value.slot] + } + if (entryClass == null) { + elementClassValid = false + } else if (elementClass == null) { + elementClass = entryClass + } else if (elementClass != entryClass) { + elementClassValid = false + } emitMove(value, entrySlots[index]) spreads.add(entry is net.sergeych.lyng.ListEntry.Spread) } @@ -886,6 +915,9 @@ class BytecodeCompiler( builder.emit(Opcode.LIST_LITERAL, planId, baseSlot, count, dst) updateSlotType(dst, SlotType.OBJ) slotObjClass[dst] = ObjList.type + if (elementClassValid && elementClass != null) { + listElementClassBySlot[dst] = elementClass + } return CompiledValue(dst, SlotType.OBJ) } @@ -1122,7 +1154,7 @@ class BytecodeCompiler( val receiverObj = ensureObjSlot(leftValue) val argObj = ensureObjSlot(rightValue) val dst = allocSlot() - builder.emit(objOpcode, receiverObj.slot, argObj.slot, dst) + emitObjArithmetic(objOpcode, receiverObj.slot, argObj.slot, dst) updateSlotType(dst, SlotType.OBJ) return CompiledValue(dst, SlotType.OBJ) } @@ -1152,7 +1184,7 @@ class BytecodeCompiler( val receiverObj = ensureObjSlot(leftValue) val argObj = ensureObjSlot(rightValue) val dst = allocSlot() - builder.emit(objOpcode, receiverObj.slot, argObj.slot, dst) + emitObjArithmetic(objOpcode, receiverObj.slot, argObj.slot, dst) updateSlotType(dst, SlotType.OBJ) return CompiledValue(dst, SlotType.OBJ) } @@ -1206,7 +1238,15 @@ class BytecodeCompiler( val endLabel = builder.label() val eqSlot = allocSlot() - builder.emit(Opcode.CMP_EQ_OBJ, leftObj.slot, rightObj.slot, eqSlot) + compileCompareObjSpecial( + Opcode.CMP_EQ_OBJ, + Opcode.CMP_EQ_STR, + Opcode.CMP_EQ_INT_OBJ, + Opcode.CMP_EQ_REAL_OBJ, + leftObj, + rightObj, + eqSlot + ) val eqLabel = builder.label() builder.emit( Opcode.JMP_IF_TRUE, @@ -1214,7 +1254,15 @@ class BytecodeCompiler( ) val ltSlot = allocSlot() - builder.emit(Opcode.CMP_LT_OBJ, leftObj.slot, rightObj.slot, ltSlot) + compileCompareObjSpecial( + Opcode.CMP_LT_OBJ, + Opcode.CMP_LT_STR, + Opcode.CMP_LT_INT_OBJ, + Opcode.CMP_LT_REAL_OBJ, + leftObj, + rightObj, + ltSlot + ) val ltLabel = builder.label() builder.emit( Opcode.JMP_IF_TRUE, @@ -1222,7 +1270,15 @@ class BytecodeCompiler( ) val gtSlot = allocSlot() - builder.emit(Opcode.CMP_GT_OBJ, leftObj.slot, rightObj.slot, gtSlot) + compileCompareObjSpecial( + Opcode.CMP_GT_OBJ, + Opcode.CMP_GT_STR, + Opcode.CMP_GT_INT_OBJ, + Opcode.CMP_GT_REAL_OBJ, + leftObj, + rightObj, + gtSlot + ) val gtLabel = builder.label() builder.emit( Opcode.JMP_IF_TRUE, @@ -1615,6 +1671,392 @@ class BytecodeCompiler( return null } + private fun compileCompareObjSpecial( + objOp: Opcode, + stringOp: Opcode, + intOp: Opcode, + realOp: Opcode, + a: CompiledValue, + b: CompiledValue, + out: Int + ): CompiledValue { + val left = ensureObjSlot(a) + val right = ensureObjSlot(b) + val opcode = when { + isExactNonNullSlotClass(left.slot, ObjString.type) && + isExactNonNullSlotClass(right.slot, ObjString.type) -> stringOp + isExactNonNullSlotClass(left.slot, ObjInt.type) && + isExactNonNullSlotClass(right.slot, ObjInt.type) -> intOp + isExactNonNullSlotClass(left.slot, ObjReal.type) && + isExactNonNullSlotClass(right.slot, ObjReal.type) -> realOp + else -> objOp + } + builder.emit(opcode, left.slot, right.slot, out) + return CompiledValue(out, SlotType.BOOL) + } + + private fun isExactNonNullSlotClass(slot: Int, expected: ObjClass): Boolean { + if (slotObjClass[slot] != expected) return false + if (!expected.isClosed) return false + val decl = typeDeclForSlot(slot) ?: return false + if (decl.isNullable) return false + val declClass = when (decl) { + is TypeDecl.Simple -> resolveTypeNameClass(decl.name) + is TypeDecl.Generic -> resolveTypeNameClass(decl.name) + else -> null + } + return declClass == expected + } + + private fun isExactNonNullSlotClassOrTemp(slot: Int, expected: ObjClass): Boolean { + if (slotObjClass[slot] != expected) return false + if (!expected.isClosed) return false + val decl = typeDeclForSlot(slot) + if (decl == null) { + if (slot < scopeSlotCount) return false + val localIndex = slot - scopeSlotCount + return localSlotKeyByIndex.getOrNull(localIndex) == null && stableObjSlots.contains(slot) + } + if (decl.isNullable) return false + val declClass = when (decl) { + is TypeDecl.Simple -> resolveTypeNameClass(decl.name) + is TypeDecl.Generic -> resolveTypeNameClass(decl.name) + else -> null + } + return declClass == expected + } + + private fun isTempSlot(slot: Int): Boolean { + if (slot < scopeSlotCount) return false + val localIndex = slot - scopeSlotCount + return localSlotKeyByIndex.getOrNull(localIndex) == null + } + + private fun isStablePrimitiveSourceSlot(slot: Int): Boolean { + if (isTempSlot(slot)) return true + if (slot < scopeSlotCount) return false + val localIndex = slot - scopeSlotCount + val key = localSlotKeyByIndex.getOrNull(localIndex) ?: return true + val info = localSlotInfoMap[key] ?: return false + return !info.isMutable + } + + private enum class NumericKind { + INT, + REAL, + UNKNOWN + } + + private fun numericKindFromSlot(slot: Int): NumericKind { + return when (slotTypes[slot]) { + SlotType.INT -> NumericKind.INT + SlotType.REAL -> NumericKind.REAL + else -> NumericKind.UNKNOWN + } + } + + private fun numericKindFromConst(value: Obj): NumericKind { + return when (value) { + is ObjInt -> NumericKind.INT + is ObjReal -> NumericKind.REAL + else -> NumericKind.UNKNOWN + } + } + + private fun inferNumericKind(ref: ObjRef): NumericKind { + return when (ref) { + is ConstRef -> numericKindFromConst(ref.constValue) + is LocalVarRef -> resolveDirectNameSlot(ref.name)?.let { numericKindFromSlot(it.slot) } ?: NumericKind.UNKNOWN + is FastLocalVarRef -> resolveDirectNameSlot(ref.name)?.let { numericKindFromSlot(it.slot) } ?: NumericKind.UNKNOWN + is LocalSlotRef -> resolveSlot(ref)?.let { numericKindFromSlot(it) } ?: NumericKind.UNKNOWN + is UnaryOpRef -> inferNumericKind(ref.a) + is BinaryOpRef -> { + val op = ref.op + if (op == BinOp.PLUS || op == BinOp.MINUS || op == BinOp.STAR || op == BinOp.SLASH || op == BinOp.PERCENT) { + val left = inferNumericKind(ref.left) + val right = inferNumericKind(ref.right) + when { + left == NumericKind.REAL || right == NumericKind.REAL -> NumericKind.REAL + left == NumericKind.INT && right == NumericKind.INT -> NumericKind.INT + else -> NumericKind.UNKNOWN + } + } else { + NumericKind.UNKNOWN + } + } + is ConditionalRef -> { + val a = inferNumericKind(ref.ifTrue) + val b = inferNumericKind(ref.ifFalse) + when { + a == NumericKind.REAL && b == NumericKind.REAL -> NumericKind.REAL + a == NumericKind.INT && b == NumericKind.INT -> NumericKind.INT + else -> NumericKind.UNKNOWN + } + } + is ElvisRef -> { + val a = inferNumericKind(ref.left) + val b = inferNumericKind(ref.right) + when { + a == NumericKind.REAL && b == NumericKind.REAL -> NumericKind.REAL + a == NumericKind.INT && b == NumericKind.INT -> NumericKind.INT + else -> NumericKind.UNKNOWN + } + } + is StatementRef -> inferNumericKindFromStatement(ref.statement) + else -> NumericKind.UNKNOWN + } + } + + private fun inferNumericKindFromStatement(stmt: Statement): NumericKind { + val target = if (stmt is BytecodeStatement) stmt.original else stmt + return when (target) { + is ExpressionStatement -> inferNumericKind(target.ref) + else -> NumericKind.UNKNOWN + } + } + + private fun resolveAssignableSlot(ref: ObjRef): Int? { + return when (ref) { + is LocalSlotRef -> resolveSlot(ref) + is LocalVarRef -> resolveAssignableSlotByName(ref.name)?.first + is FastLocalVarRef -> resolveAssignableSlotByName(ref.name)?.first + else -> null + } + } + + private fun collectLoopRealWidenSlots(stmt: Statement): Set { + val widened = linkedSetOf() + + fun noteAssignment(target: ObjRef, value: ObjRef) { + val slot = resolveAssignableSlot(target) ?: return + if (numericKindFromSlot(slot) != NumericKind.INT) return + if (inferNumericKind(value) == NumericKind.REAL) { + widened.add(slot) + } + } + + lateinit var scanStatement: (Statement) -> Unit + lateinit var scanRef: (ObjRef) -> Unit + + scanRef = { ref -> + when (ref) { + is AssignRef -> noteAssignment(ref.target, ref.value) + is AssignOpRef -> noteAssignment(ref.target, ref.value) + is IncDecRef -> {} + is UnaryOpRef -> scanRef(ref.a) + is BinaryOpRef -> { + scanRef(ref.left) + scanRef(ref.right) + } + is ConditionalRef -> { + scanRef(ref.condition) + scanRef(ref.ifTrue) + scanRef(ref.ifFalse) + } + is ElvisRef -> { + scanRef(ref.left) + scanRef(ref.right) + } + is LogicalAndRef -> { + scanRef(ref.left()) + scanRef(ref.right()) + } + is LogicalOrRef -> { + scanRef(ref.left()) + scanRef(ref.right()) + } + is CastRef -> scanRef(ref.castValueRef()) + is RangeRef -> { + ref.left?.let { scanRef(it) } + ref.right?.let { scanRef(it) } + ref.step?.let { scanRef(it) } + } + is CallRef -> { + scanRef(ref.target) + ref.args.forEach { arg -> + (arg.value as? ObjRef)?.let { scanRef(it) } + } + } + is MethodCallRef -> { + scanRef(ref.receiver) + ref.args.forEach { arg -> + (arg.value as? ObjRef)?.let { scanRef(it) } + } + } + is FieldRef -> scanRef(ref.target) + is IndexRef -> { + scanRef(ref.targetRef) + scanRef(ref.indexRef) + } + is StatementRef -> scanStatement(ref.statement) + is ListLiteralRef -> ref.entries().forEach { entry -> + when (entry) { + is ListEntry.Element -> scanRef(entry.ref) + is ListEntry.Spread -> scanRef(entry.ref) + } + } + is MapLiteralRef -> ref.entries().forEach { entry -> + when (entry) { + is MapLiteralEntry.Named -> scanRef(entry.value) + is MapLiteralEntry.Spread -> scanRef(entry.ref) + } + } + else -> {} + } + } + + scanStatement = { statement -> + val target = if (statement is BytecodeStatement) statement.original else statement + when (target) { + is ExpressionStatement -> scanRef(target.ref) + is BlockStatement -> target.statements().forEach { scanStatement(it) } + is InlineBlockStatement -> target.statements().forEach { scanStatement(it) } + is IfStatement -> { + scanStatement(target.condition) + scanStatement(target.ifBody) + target.elseBody?.let { scanStatement(it) } + } + is WhenStatement -> { + scanStatement(target.value) + target.cases.forEach { case -> + case.conditions.forEach { scanStatement(it.expr) } + scanStatement(case.block) + } + target.elseCase?.let { scanStatement(it) } + } + is WhileStatement -> { + scanStatement(target.condition) + scanStatement(target.body) + target.elseStatement?.let { scanStatement(it) } + } + is DoWhileStatement -> { + scanStatement(target.body) + scanStatement(target.condition) + target.elseStatement?.let { scanStatement(it) } + } + is ForInStatement -> { + scanStatement(target.source) + scanStatement(target.body) + target.elseStatement?.let { scanStatement(it) } + } + is TryStatement -> { + scanStatement(target.body) + target.catches.forEach { scanStatement(it.block) } + target.finallyClause?.let { scanStatement(it) } + } + is ReturnStatement -> target.resultExpr?.let { scanStatement(it) } + is ThrowStatement -> scanStatement(target.throwExpr) + else -> {} + } + } + + scanStatement(stmt) + return widened + } + + private fun rememberSlotTypes(slots: Set): Map { + if (slots.isEmpty()) return emptyMap() + val result = LinkedHashMap(slots.size) + for (slot in slots) { + result[slot] = slotTypes[slot] + } + return result + } + + private fun applySlotTypes(slots: Set, type: SlotType) { + for (slot in slots) { + updateSlotType(slot, type) + } + } + + private fun restoreSlotTypes(previous: Map) { + for ((slot, type) in previous) { + if (type == null) { + updateSlotType(slot, SlotType.UNKNOWN) + } else { + updateSlotType(slot, type) + } + } + } + + private fun emitLoopRealCoercions(slots: Set) { + for (slot in slots) { + builder.emit(Opcode.INT_TO_REAL, slot, slot) + updateSlotType(slot, SlotType.REAL) + } + } + + private fun objArithmeticOpcode(base: Opcode, forReal: Boolean): Opcode { + return when (base) { + Opcode.ADD_OBJ -> if (forReal) Opcode.ADD_REAL_OBJ else Opcode.ADD_INT_OBJ + Opcode.SUB_OBJ -> if (forReal) Opcode.SUB_REAL_OBJ else Opcode.SUB_INT_OBJ + Opcode.MUL_OBJ -> if (forReal) Opcode.MUL_REAL_OBJ else Opcode.MUL_INT_OBJ + Opcode.DIV_OBJ -> if (forReal) Opcode.DIV_REAL_OBJ else Opcode.DIV_INT_OBJ + Opcode.MOD_OBJ -> if (forReal) Opcode.MOD_REAL_OBJ else Opcode.MOD_INT_OBJ + else -> base + } + } + + private fun coerceObjIntToObjReal(slot: Int): Int { + val intSlot = allocSlot() + builder.emit(Opcode.UNBOX_INT_OBJ, slot, intSlot) + updateSlotType(intSlot, SlotType.INT) + val realSlot = allocSlot() + builder.emit(Opcode.INT_TO_REAL, intSlot, realSlot) + updateSlotType(realSlot, SlotType.REAL) + val objSlot = allocSlot() + builder.emit(Opcode.BOX_OBJ, realSlot, objSlot) + updateSlotType(objSlot, SlotType.OBJ) + slotObjClass[objSlot] = ObjReal.type + return objSlot + } + + private fun emitObjArithmetic(base: Opcode, leftSlot: Int, rightSlot: Int, dst: Int) { + val fastEligible = isTempSlot(leftSlot) && isTempSlot(rightSlot) && isTempSlot(dst) + val leftInt = isExactNonNullSlotClassOrTemp(leftSlot, ObjInt.type) + val rightInt = isExactNonNullSlotClassOrTemp(rightSlot, ObjInt.type) + val leftReal = isExactNonNullSlotClassOrTemp(leftSlot, ObjReal.type) + val rightReal = isExactNonNullSlotClassOrTemp(rightSlot, ObjReal.type) + if (fastEligible && leftInt && rightInt) { + builder.emit(objArithmeticOpcode(base, forReal = false), leftSlot, rightSlot, dst) + slotObjClass[dst] = ObjInt.type + stableObjSlots.add(dst) + return + } + if (fastEligible && leftReal && rightReal) { + builder.emit(objArithmeticOpcode(base, forReal = true), leftSlot, rightSlot, dst) + slotObjClass[dst] = ObjReal.type + stableObjSlots.add(dst) + return + } + if (fastEligible && leftInt && rightReal) { + val coerced = coerceObjIntToObjReal(leftSlot) + builder.emit(objArithmeticOpcode(base, forReal = true), coerced, rightSlot, dst) + slotObjClass[dst] = ObjReal.type + stableObjSlots.add(dst) + return + } + if (fastEligible && leftReal && rightInt) { + val coerced = coerceObjIntToObjReal(rightSlot) + builder.emit(objArithmeticOpcode(base, forReal = true), leftSlot, coerced, dst) + slotObjClass[dst] = ObjReal.type + stableObjSlots.add(dst) + return + } + builder.emit(base, leftSlot, rightSlot, dst) + slotObjClass.remove(dst) + stableObjSlots.remove(dst) + } + + private fun typeDeclForSlot(slot: Int): TypeDecl? { + val key = if (slot < scopeSlotCount) { + scopeKeyByIndex.getOrNull(slot) + } else { + localSlotKeyByIndex.getOrNull(slot - scopeSlotCount) + } ?: return null + return slotTypeDeclByScopeId[key.scopeId]?.get(key.slot) + } + private fun compileCompareEq(a: CompiledValue, b: CompiledValue, out: Int): CompiledValue? { if (a.type == SlotType.UNKNOWN || b.type == SlotType.UNKNOWN) { val left = ensureObjSlot(a) @@ -1623,10 +2065,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_EQ_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_EQ_OBJ, + Opcode.CMP_EQ_STR, + Opcode.CMP_EQ_INT_OBJ, + Opcode.CMP_EQ_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -1665,10 +2112,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_NEQ_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_NEQ_OBJ, + Opcode.CMP_NEQ_STR, + Opcode.CMP_NEQ_INT_OBJ, + Opcode.CMP_NEQ_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -1707,10 +2159,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_LT_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_LT_OBJ, + Opcode.CMP_LT_STR, + Opcode.CMP_LT_INT_OBJ, + Opcode.CMP_LT_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -1745,10 +2202,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_LTE_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_LTE_OBJ, + Opcode.CMP_LTE_STR, + Opcode.CMP_LTE_INT_OBJ, + Opcode.CMP_LTE_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -1783,10 +2245,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_GT_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_GT_OBJ, + Opcode.CMP_GT_STR, + Opcode.CMP_GT_INT_OBJ, + Opcode.CMP_GT_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -1821,10 +2288,15 @@ class BytecodeCompiler( return CompiledValue(out, SlotType.BOOL) } if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) { - val left = ensureObjSlot(a) - val right = ensureObjSlot(b) - builder.emit(Opcode.CMP_GTE_OBJ, left.slot, right.slot, out) - return CompiledValue(out, SlotType.BOOL) + return compileCompareObjSpecial( + Opcode.CMP_GTE_OBJ, + Opcode.CMP_GTE_STR, + Opcode.CMP_GTE_INT_OBJ, + Opcode.CMP_GTE_REAL_OBJ, + a, + b, + out + ) } return when { a.type == SlotType.INT && b.type == SlotType.INT -> { @@ -3094,6 +3566,10 @@ class BytecodeCompiler( builder.mark(endLabel) } updateSlotType(dst, SlotType.OBJ) + val elementClass = listElementClassBySlot[receiver.slot] ?: listElementClassFromReceiverRef(ref.targetRef) + if (elementClass != null) { + slotObjClass[dst] = elementClass + } return CompiledValue(dst, SlotType.OBJ) } @@ -3161,7 +3637,9 @@ class BytecodeCompiler( if (objOp == null) return null val leftObj = allocSlot() builder.emit(Opcode.BOX_OBJ, out, leftObj) - builder.emit(objOp, leftObj, rhs.slot, out) + updateSlotType(leftObj, SlotType.OBJ) + slotObjClass[leftObj] = ObjInt.type + emitObjArithmetic(objOp, leftObj, rhs.slot, out) CompiledValue(out, SlotType.OBJ) } else -> null @@ -3184,7 +3662,9 @@ class BytecodeCompiler( if (objOp == null) return null val leftObj = allocSlot() builder.emit(Opcode.BOX_OBJ, out, leftObj) - builder.emit(objOp, leftObj, rhs.slot, out) + updateSlotType(leftObj, SlotType.OBJ) + slotObjClass[leftObj] = ObjReal.type + emitObjArithmetic(objOp, leftObj, rhs.slot, out) CompiledValue(out, SlotType.OBJ) } else -> null @@ -3193,7 +3673,7 @@ class BytecodeCompiler( SlotType.OBJ -> { if (objOp == null) return null if (rhs.type != SlotType.OBJ) return null - builder.emit(objOp, out, rhs.slot, out) + emitObjArithmetic(objOp, out, rhs.slot, out) CompiledValue(out, SlotType.OBJ) } else -> null @@ -3880,6 +4360,33 @@ class BytecodeCompiler( val dst = allocSlot() builder.emit(Opcode.BOX_OBJ, value.slot, dst) updateSlotType(dst, SlotType.OBJ) + when (value.type) { + SlotType.INT -> { + slotObjClass[dst] = ObjInt.type + if (isStablePrimitiveSourceSlot(value.slot)) { + stableObjSlots.add(dst) + } else { + stableObjSlots.remove(dst) + } + } + SlotType.REAL -> { + slotObjClass[dst] = ObjReal.type + if (isStablePrimitiveSourceSlot(value.slot)) { + stableObjSlots.add(dst) + } else { + stableObjSlots.remove(dst) + } + } + SlotType.BOOL -> { + slotObjClass[dst] = ObjBool.type + if (isStablePrimitiveSourceSlot(value.slot)) { + stableObjSlots.add(dst) + } else { + stableObjSlots.remove(dst) + } + } + else -> stableObjSlots.remove(dst) + } return CompiledValue(dst, SlotType.OBJ) } @@ -5211,6 +5718,8 @@ class BytecodeCompiler( } updateSlotType(localSlot, value.type) updateSlotObjClass(localSlot, stmt.initializer, stmt.initializerObjClass) + updateListElementClassFromDecl(localSlot, scopeId, stmt.slotIndex) + updateListElementClassFromInitializer(localSlot, stmt.initializer) updateNameObjClassFromSlot(stmt.name, localSlot) val shadowedScopeSlot = scopeSlotIndexByName.containsKey(stmt.name) val isModuleScope = moduleScopeId != null && scopeId == moduleScopeId @@ -5240,6 +5749,8 @@ class BytecodeCompiler( updateSlotType(scopeSlot, value.type) updateNameObjClassFromSlot(stmt.name, scopeSlot) updateSlotObjClass(scopeSlot, stmt.initializer, stmt.initializerObjClass) + updateListElementClassFromDecl(scopeSlot, scopeId, stmt.slotIndex) + updateListElementClassFromInitializer(scopeSlot, stmt.initializer) val declId = builder.addConst( BytecodeConst.LocalDecl( stmt.name, @@ -5272,6 +5783,8 @@ class BytecodeCompiler( } updateNameObjClassFromSlot(stmt.name, value.slot) updateSlotObjClass(value.slot, stmt.initializer, stmt.initializerObjClass) + updateListElementClassFromDecl(value.slot, scopeId, stmt.slotIndex) + updateListElementClassFromInitializer(value.slot, stmt.initializer) return value } @@ -5347,6 +5860,18 @@ class BytecodeCompiler( } } + private fun updateListElementClassFromDecl(slot: Int, scopeId: Int, slotIndex: Int?) { + if (slotIndex == null) return + val decl = slotTypeDeclByScopeId[scopeId]?.get(slotIndex) ?: return + val elementClass = listElementClassFromDecl(decl) ?: return + listElementClassBySlot[slot] = elementClass + } + + private fun updateListElementClassFromInitializer(slot: Int, initializer: Statement?) { + val elementClass = listElementClassFromInitializer(initializer) ?: return + listElementClassBySlot[slot] = elementClass + } + private fun updateNameObjClassFromSlot(name: String, slot: Int) { val cls = slotObjClass[slot] ?: return nameObjClass[name] = cls @@ -5401,6 +5926,41 @@ class BytecodeCompiler( else -> null } } + + private fun listElementClassFromInitializer(initializer: Statement?): ObjClass? { + var initStmt = initializer + while (initStmt is BytecodeStatement) { + initStmt = initStmt.original + } + val initRef = (initStmt as? ExpressionStatement)?.ref + val directRef = when (initRef) { + is StatementRef -> (initRef.statement as? ExpressionStatement)?.ref + else -> initRef + } + return when (directRef) { + is ListLiteralRef -> listElementClassFromListLiteralRef(directRef) + else -> null + } + } + + private fun listElementClassFromListLiteralRef(ref: ListLiteralRef): ObjClass? { + var elementClass: ObjClass? = null + for (entry in ref.entries()) { + val entryClass = when (entry) { + is net.sergeych.lyng.ListEntry.Element -> { + val const = entry.ref as? ConstRef ?: return null + elementClassFromConst(const.constValue) + } + is net.sergeych.lyng.ListEntry.Spread -> return null + } ?: return null + if (elementClass == null) { + elementClass = entryClass + } else if (elementClass != entryClass) { + return null + } + } + return elementClass + } private fun emitForIn(stmt: net.sergeych.lyng.ForInStatement, wantResult: Boolean): Int? { val range = stmt.constRange var rangeRef = if (range == null) extractRangeRef(stmt.source) else null @@ -5749,6 +6309,12 @@ class BytecodeCompiler( val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid)) builder.emit(Opcode.CONST_OBJ, voidId, resultSlot) + val realWidenSlots = collectLoopRealWidenSlots(stmt.body) + val hasRealWiden = realWidenSlots.isNotEmpty() + if (hasRealWiden) { + applySlotTypes(realWidenSlots, SlotType.REAL) + } + val loopLabel = builder.label() val continueLabel = builder.label() val endLabel = builder.label() @@ -5771,9 +6337,12 @@ class BytecodeCompiler( builder.emit(Opcode.MOVE_OBJ, bodyObj.slot, resultSlot) } builder.mark(continueLabel) + if (hasRealWiden) { + emitLoopRealCoercions(realWidenSlots) + } val conditionTarget = if (stmt.condition is BytecodeStatement) stmt.condition.original else stmt.condition val conditionStmt = conditionTarget as? ExpressionStatement ?: return null - if (!emitIntCompareJump(conditionStmt.ref, jumpOnTrue = true, target = loopLabel)) { + if (hasRealWiden || !emitIntCompareJump(conditionStmt.ref, jumpOnTrue = true, target = loopLabel)) { val condition = compileRefWithFallback(conditionStmt.ref, SlotType.BOOL, stmt.pos) ?: return null if (condition.type != SlotType.BOOL) return null builder.emit( @@ -5808,11 +6377,20 @@ class BytecodeCompiler( val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid)) builder.emit(Opcode.CONST_OBJ, voidId, resultSlot) + val realWidenSlots = collectLoopRealWidenSlots(stmt.body) + val hasRealWiden = realWidenSlots.isNotEmpty() + if (hasRealWiden) { + applySlotTypes(realWidenSlots, SlotType.REAL) + } + val loopLabel = builder.label() val continueLabel = builder.label() val endLabel = builder.label() val breakLabel = endLabel builder.mark(loopLabel) + if (hasRealWiden) { + emitLoopRealCoercions(realWidenSlots) + } loopStack.addLast( LoopContext( stmt.label, @@ -6269,11 +6847,24 @@ class BytecodeCompiler( val cls = slotObjClass[srcSlot] if (cls != null) { slotObjClass[dstSlot] = cls + if (stableObjSlots.contains(srcSlot)) { + stableObjSlots.add(dstSlot) + } else { + stableObjSlots.remove(dstSlot) + } } else { slotObjClass.remove(dstSlot) + stableObjSlots.remove(dstSlot) + } + val elementClass = listElementClassBySlot[srcSlot] + if (elementClass != null) { + listElementClassBySlot[dstSlot] = elementClass + } else { + listElementClassBySlot.remove(dstSlot) } } else { slotObjClass.remove(dstSlot) + listElementClassBySlot.remove(dstSlot) } } @@ -6815,8 +7406,12 @@ class BytecodeCompiler( if (forcedObjSlots.contains(slot) && type != SlotType.OBJ) return if (type == SlotType.UNKNOWN) { slotTypes.remove(slot) + listElementClassBySlot.remove(slot) } else { slotTypes[slot] = type + if (type != SlotType.OBJ) { + listElementClassBySlot.remove(slot) + } } } @@ -6829,6 +7424,56 @@ class BytecodeCompiler( } } + private fun elementClassFromValue(value: CompiledValue): ObjClass? { + val cls = when (value.type) { + SlotType.INT -> ObjInt.type + SlotType.REAL -> ObjReal.type + SlotType.BOOL -> ObjBool.type + SlotType.OBJ, SlotType.UNKNOWN -> slotObjClass[value.slot] + } + return when (cls) { + ObjInt.type, ObjReal.type, ObjString.type, ObjBool.type -> cls + else -> null + } + } + + private fun elementClassFromConst(value: Obj): ObjClass? { + return when (value) { + is ObjInt -> ObjInt.type + is ObjReal -> ObjReal.type + is ObjString -> ObjString.type + is ObjBool -> ObjBool.type + else -> null + } + } + + private fun listElementClassFromDecl(decl: TypeDecl): ObjClass? { + val generic = decl as? TypeDecl.Generic ?: return null + if (generic.name != "List" || generic.args.size != 1) return null + val arg = generic.args.first() + val cls = when (arg) { + is TypeDecl.Simple -> resolveTypeNameClass(arg.name) + is TypeDecl.Generic -> resolveTypeNameClass(arg.name) + else -> null + } + return when (cls) { + ObjInt.type, ObjReal.type, ObjString.type, ObjBool.type -> cls + else -> null + } + } + + private fun listElementClassFromReceiverRef(ref: ObjRef): ObjClass? { + return when (ref) { + is LocalSlotRef -> { + val scopeId = refScopeId(ref) + val slot = refSlot(ref) + val decl = slotTypeDeclByScopeId[scopeId]?.get(slot) ?: return null + listElementClassFromDecl(decl) + } + else -> null + } + } + private fun prepareCompilation(stmt: Statement) { builder = CmdBuilder() nextSlot = 0 @@ -6836,6 +7481,7 @@ class BytecodeCompiler( slotTypes.clear() slotObjClass.clear() nameObjClass.clear() + listElementClassBySlot.clear() if (knownNameObjClass.isNotEmpty()) { nameObjClass.putAll(knownNameObjClass) } @@ -6851,10 +7497,12 @@ class BytecodeCompiler( loopSlotOverrides.clear() scopeSlotIndexByName.clear() pendingScopeNameRefs.clear() + scopeKeyByIndex = emptyArray() localSlotNames = emptyArray() localSlotMutables = BooleanArray(0) localSlotDelegated = BooleanArray(0) localSlotCaptures = BooleanArray(0) + localSlotKeyByIndex = emptyArray() declaredLocalKeys.clear() localRangeRefs.clear() intLoopVarNames.clear() @@ -6870,6 +7518,25 @@ class BytecodeCompiler( } } } + if (slotTypeDeclByScopeId.isNotEmpty()) { + for ((scopeId, slots) in slotTypeDeclByScopeId) { + for ((slotIndex, decl) in slots) { + if (decl.isNullable) continue + val key = ScopeSlotKey(scopeId, slotIndex) + if (slotInitClassByKey.containsKey(key)) continue + val cls = when (decl) { + is TypeDecl.Simple -> resolveTypeNameClass(decl.name) + is TypeDecl.Generic -> resolveTypeNameClass(decl.name) + else -> null + } + when (cls) { + ObjInt.type, ObjReal.type, ObjString.type, ObjBool.type -> { + slotInitClassByKey[key] = cls + } + } + } + } + } if (allowLocalSlots) { collectLoopVarNames(stmt) } @@ -6942,12 +7609,14 @@ class BytecodeCompiler( scopeSlotNames = arrayOfNulls(scopeSlotCount) scopeSlotIsModule = BooleanArray(scopeSlotCount) scopeSlotMutables = BooleanArray(scopeSlotCount) { true } + scopeKeyByIndex = arrayOfNulls(scopeSlotCount) for ((key, index) in scopeSlotMap) { val name = scopeSlotNameMap[key] scopeSlotIndices[index] = key.slot scopeSlotNames[index] = name scopeSlotIsModule[index] = moduleScopeId != null && key.scopeId == moduleScopeId scopeSlotMutableMap[key]?.let { scopeSlotMutables[index] = it } + scopeKeyByIndex[index] = key } if (allowLocalSlots && localSlotInfoMap.isNotEmpty()) { val moduleId = moduleScopeId @@ -7037,6 +7706,14 @@ class BytecodeCompiler( localSlotDelegated = delegated } } + if (allowLocalSlots) { + localSlotKeyByIndex = arrayOfNulls(localSlotNames.size) + for ((key, index) in localSlotIndexByKey) { + if (index in localSlotKeyByIndex.indices) { + localSlotKeyByIndex[index] = key + } + } + } if (allowLocalSlots && captureSlotKeys.isNotEmpty() && slotInitClassByKey.isNotEmpty()) { val scopeSlotsBase = scopeSlotMap.size for (key in captureSlotKeys) { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeStatement.kt index fb1848d..26ca319 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeStatement.kt @@ -59,6 +59,7 @@ class BytecodeStatement private constructor( callableReturnTypeByName: Map = emptyMap(), externCallableNames: Set = emptySet(), lambdaCaptureEntriesByRef: Map> = emptyMap(), + slotTypeDeclByScopeId: Map> = emptyMap(), ): Statement { if (statement is BytecodeStatement) return statement val hasUnsupported = containsUnsupportedStatement(statement) @@ -83,6 +84,7 @@ class BytecodeStatement private constructor( globalSlotInfo = globalSlotInfo, globalSlotScopeId = globalSlotScopeId, slotTypeByScopeId = slotTypeByScopeId, + slotTypeDeclByScopeId = slotTypeDeclByScopeId, knownNameObjClass = knownNameObjClass, knownObjectNames = knownObjectNames, classFieldTypesByName = classFieldTypesByName, diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt index 6bb2b5d..6d60eb1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt @@ -102,7 +102,7 @@ class CmdBuilder { } operands[i] = v } - cmds.add(createCmd(ins.op, operands, scopeSlotCount)) + cmds.add(createCmd(ins.op, operands, scopeSlotCount, localSlotCaptures)) } return CmdFunction( name = name, @@ -128,6 +128,7 @@ class CmdBuilder { Opcode.NOP, Opcode.RET_VOID, Opcode.POP_SCOPE, Opcode.POP_SLOT_PLAN, Opcode.POP_TRY, Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING -> emptyList() Opcode.MOVE_OBJ, Opcode.MOVE_INT, Opcode.MOVE_REAL, Opcode.MOVE_BOOL, Opcode.BOX_OBJ, + Opcode.UNBOX_INT_OBJ, Opcode.UNBOX_REAL_OBJ, Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL, Opcode.OBJ_TO_BOOL, Opcode.GET_OBJ_CLASS, Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT, @@ -179,7 +180,14 @@ class CmdBuilder { Opcode.CMP_LTE_INT_REAL, Opcode.CMP_LTE_REAL_INT, Opcode.CMP_GT_INT_REAL, Opcode.CMP_GT_REAL_INT, Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT, Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ, + Opcode.CMP_EQ_STR, Opcode.CMP_NEQ_STR, Opcode.CMP_LT_STR, Opcode.CMP_LTE_STR, + Opcode.CMP_GT_STR, Opcode.CMP_GTE_STR, + Opcode.CMP_EQ_INT_OBJ, Opcode.CMP_NEQ_INT_OBJ, Opcode.CMP_LT_INT_OBJ, Opcode.CMP_LTE_INT_OBJ, + Opcode.CMP_GT_INT_OBJ, Opcode.CMP_GTE_INT_OBJ, Opcode.CMP_EQ_REAL_OBJ, Opcode.CMP_NEQ_REAL_OBJ, + Opcode.CMP_LT_REAL_OBJ, Opcode.CMP_LTE_REAL_OBJ, Opcode.CMP_GT_REAL_OBJ, Opcode.CMP_GTE_REAL_OBJ, Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ, + Opcode.ADD_INT_OBJ, Opcode.SUB_INT_OBJ, Opcode.MUL_INT_OBJ, Opcode.DIV_INT_OBJ, Opcode.MOD_INT_OBJ, + Opcode.ADD_REAL_OBJ, Opcode.SUB_REAL_OBJ, Opcode.MUL_REAL_OBJ, Opcode.DIV_REAL_OBJ, Opcode.MOD_REAL_OBJ, Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ, Opcode.AND_BOOL, Opcode.OR_BOOL -> listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) @@ -241,19 +249,37 @@ class CmdBuilder { ID, } - private fun createCmd(op: Opcode, operands: IntArray, scopeSlotCount: Int): Cmd { + private fun createCmd( + op: Opcode, + operands: IntArray, + scopeSlotCount: Int, + localSlotCaptures: BooleanArray + ): Cmd { + fun isFastLocal(slot: Int): Boolean { + if (slot < scopeSlotCount) return false + val localIndex = slot - scopeSlotCount + return localSlotCaptures.getOrNull(localIndex) != true + } return when (op) { Opcode.NOP -> CmdNop() Opcode.MOVE_OBJ -> CmdMoveObj(operands[0], operands[1]) - Opcode.MOVE_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount) { + Opcode.MOVE_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { CmdMoveIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) } else { CmdMoveInt(operands[0], operands[1]) } - Opcode.MOVE_REAL -> CmdMoveReal(operands[0], operands[1]) - Opcode.MOVE_BOOL -> CmdMoveBool(operands[0], operands[1]) + Opcode.MOVE_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdMoveRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdMoveReal(operands[0], operands[1]) + } + Opcode.MOVE_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdMoveBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdMoveBool(operands[0], operands[1]) + } Opcode.CONST_OBJ -> CmdConstObj(operands[0], operands[1]) - Opcode.CONST_INT -> if (operands[1] >= scopeSlotCount) { + Opcode.CONST_INT -> if (isFastLocal(operands[1])) { CmdConstIntLocal(operands[0], operands[1] - scopeSlotCount) } else { CmdConstInt(operands[0], operands[1]) @@ -263,6 +289,16 @@ class CmdBuilder { Opcode.CONST_NULL -> CmdConstNull(operands[0]) Opcode.MAKE_LAMBDA_FN -> CmdMakeLambda(operands[0], operands[1]) Opcode.BOX_OBJ -> CmdBoxObj(operands[0], operands[1]) + Opcode.UNBOX_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdUnboxIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdUnboxIntObj(operands[0], operands[1]) + } + Opcode.UNBOX_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdUnboxRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdUnboxRealObj(operands[0], operands[1]) + } Opcode.OBJ_TO_BOOL -> CmdObjToBool(operands[0], operands[1]) Opcode.GET_OBJ_CLASS -> CmdGetObjClass(operands[0], operands[1]) Opcode.RANGE_INT_BOUNDS -> CmdRangeIntBounds(operands[0], operands[1], operands[2], operands[3]) @@ -287,119 +323,419 @@ class CmdBuilder { Opcode.STORE_REAL_ADDR -> CmdStoreRealAddr(operands[0], operands[1]) Opcode.LOAD_BOOL_ADDR -> CmdLoadBoolAddr(operands[0], operands[1]) Opcode.STORE_BOOL_ADDR -> CmdStoreBoolAddr(operands[0], operands[1]) - Opcode.INT_TO_REAL -> CmdIntToReal(operands[0], operands[1]) - Opcode.REAL_TO_INT -> CmdRealToInt(operands[0], operands[1]) - Opcode.BOOL_TO_INT -> CmdBoolToInt(operands[0], operands[1]) - Opcode.INT_TO_BOOL -> CmdIntToBool(operands[0], operands[1]) - Opcode.ADD_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.INT_TO_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdIntToRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdIntToReal(operands[0], operands[1]) + } + Opcode.REAL_TO_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdRealToIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdRealToInt(operands[0], operands[1]) + } + Opcode.BOOL_TO_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdBoolToIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdBoolToInt(operands[0], operands[1]) + } + Opcode.INT_TO_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdIntToBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdIntToBool(operands[0], operands[1]) + } + Opcode.ADD_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdAddIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdAddInt(operands[0], operands[1], operands[2]) } - Opcode.SUB_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.SUB_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdSubIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdSubInt(operands[0], operands[1], operands[2]) } - Opcode.MUL_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.MUL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdMulIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdMulInt(operands[0], operands[1], operands[2]) } - Opcode.DIV_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.DIV_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdDivIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdDivInt(operands[0], operands[1], operands[2]) } - Opcode.MOD_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.MOD_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdModIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdModInt(operands[0], operands[1], operands[2]) } - Opcode.NEG_INT -> CmdNegInt(operands[0], operands[1]) - Opcode.INC_INT -> if (operands[0] >= scopeSlotCount) { + Opcode.NEG_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdNegIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdNegInt(operands[0], operands[1]) + } + Opcode.INC_INT -> if (isFastLocal(operands[0])) { CmdIncIntLocal(operands[0] - scopeSlotCount) } else { CmdIncInt(operands[0]) } - Opcode.DEC_INT -> if (operands[0] >= scopeSlotCount) { + Opcode.DEC_INT -> if (isFastLocal(operands[0])) { CmdDecIntLocal(operands[0] - scopeSlotCount) } else { CmdDecInt(operands[0]) } - Opcode.ADD_REAL -> CmdAddReal(operands[0], operands[1], operands[2]) - Opcode.SUB_REAL -> CmdSubReal(operands[0], operands[1], operands[2]) - Opcode.MUL_REAL -> CmdMulReal(operands[0], operands[1], operands[2]) - Opcode.DIV_REAL -> CmdDivReal(operands[0], operands[1], operands[2]) - Opcode.NEG_REAL -> CmdNegReal(operands[0], operands[1]) - Opcode.AND_INT -> CmdAndInt(operands[0], operands[1], operands[2]) - Opcode.OR_INT -> CmdOrInt(operands[0], operands[1], operands[2]) - Opcode.XOR_INT -> CmdXorInt(operands[0], operands[1], operands[2]) - Opcode.SHL_INT -> CmdShlInt(operands[0], operands[1], operands[2]) - Opcode.SHR_INT -> CmdShrInt(operands[0], operands[1], operands[2]) - Opcode.USHR_INT -> CmdUshrInt(operands[0], operands[1], operands[2]) - Opcode.INV_INT -> CmdInvInt(operands[0], operands[1]) - Opcode.CMP_EQ_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.ADD_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdAddRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdAddReal(operands[0], operands[1], operands[2]) + } + Opcode.SUB_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdSubRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdSubReal(operands[0], operands[1], operands[2]) + } + Opcode.MUL_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdMulRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdMulReal(operands[0], operands[1], operands[2]) + } + Opcode.DIV_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdDivRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdDivReal(operands[0], operands[1], operands[2]) + } + Opcode.NEG_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdNegRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdNegReal(operands[0], operands[1]) + } + Opcode.AND_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdAndIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdAndInt(operands[0], operands[1], operands[2]) + } + Opcode.OR_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdOrIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdOrInt(operands[0], operands[1], operands[2]) + } + Opcode.XOR_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdXorIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdXorInt(operands[0], operands[1], operands[2]) + } + Opcode.SHL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdShlIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdShlInt(operands[0], operands[1], operands[2]) + } + Opcode.SHR_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdShrIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdShrInt(operands[0], operands[1], operands[2]) + } + Opcode.USHR_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdUshrIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdUshrInt(operands[0], operands[1], operands[2]) + } + Opcode.INV_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdInvIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdInvInt(operands[0], operands[1]) + } + Opcode.CMP_EQ_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpEqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpEqInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_NEQ_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.CMP_NEQ_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpNeqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpNeqInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_LT_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.CMP_LT_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpLtIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpLtInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_LTE_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.CMP_LTE_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpLteIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpLteInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_GT_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.CMP_GT_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpGtIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpGtInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_GTE_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { + Opcode.CMP_GTE_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { CmdCmpGteIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) } else { CmdCmpGteInt(operands[0], operands[1], operands[2]) } - Opcode.CMP_EQ_REAL -> CmdCmpEqReal(operands[0], operands[1], operands[2]) - Opcode.CMP_NEQ_REAL -> CmdCmpNeqReal(operands[0], operands[1], operands[2]) - Opcode.CMP_LT_REAL -> CmdCmpLtReal(operands[0], operands[1], operands[2]) - Opcode.CMP_LTE_REAL -> CmdCmpLteReal(operands[0], operands[1], operands[2]) - Opcode.CMP_GT_REAL -> CmdCmpGtReal(operands[0], operands[1], operands[2]) - Opcode.CMP_GTE_REAL -> CmdCmpGteReal(operands[0], operands[1], operands[2]) - Opcode.CMP_EQ_BOOL -> CmdCmpEqBool(operands[0], operands[1], operands[2]) - Opcode.CMP_NEQ_BOOL -> CmdCmpNeqBool(operands[0], operands[1], operands[2]) - Opcode.CMP_EQ_INT_REAL -> CmdCmpEqIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_EQ_REAL_INT -> CmdCmpEqRealInt(operands[0], operands[1], operands[2]) - Opcode.CMP_LT_INT_REAL -> CmdCmpLtIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_LT_REAL_INT -> CmdCmpLtRealInt(operands[0], operands[1], operands[2]) - Opcode.CMP_LTE_INT_REAL -> CmdCmpLteIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_LTE_REAL_INT -> CmdCmpLteRealInt(operands[0], operands[1], operands[2]) - Opcode.CMP_GT_INT_REAL -> CmdCmpGtIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_GT_REAL_INT -> CmdCmpGtRealInt(operands[0], operands[1], operands[2]) - Opcode.CMP_GTE_INT_REAL -> CmdCmpGteIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_GTE_REAL_INT -> CmdCmpGteRealInt(operands[0], operands[1], operands[2]) - Opcode.CMP_NEQ_INT_REAL -> CmdCmpNeqIntReal(operands[0], operands[1], operands[2]) - Opcode.CMP_NEQ_REAL_INT -> CmdCmpNeqRealInt(operands[0], operands[1], operands[2]) + Opcode.CMP_EQ_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_EQ_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqBool(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqBool(operands[0], operands[1], operands[2]) + } + Opcode.CMP_EQ_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_EQ_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqRealInt(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtRealInt(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteRealInt(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtRealInt(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteRealInt(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_INT_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqIntRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqIntReal(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_REAL_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqRealIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqRealInt(operands[0], operands[1], operands[2]) + } Opcode.CMP_EQ_OBJ -> CmdCmpEqObj(operands[0], operands[1], operands[2]) Opcode.CMP_NEQ_OBJ -> CmdCmpNeqObj(operands[0], operands[1], operands[2]) Opcode.CMP_REF_EQ_OBJ -> CmdCmpRefEqObj(operands[0], operands[1], operands[2]) Opcode.CMP_REF_NEQ_OBJ -> CmdCmpRefNeqObj(operands[0], operands[1], operands[2]) - Opcode.NOT_BOOL -> CmdNotBool(operands[0], operands[1]) - Opcode.AND_BOOL -> CmdAndBool(operands[0], operands[1], operands[2]) - Opcode.OR_BOOL -> CmdOrBool(operands[0], operands[1], operands[2]) + Opcode.CMP_EQ_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteStr(operands[0], operands[1], operands[2]) + } + Opcode.CMP_EQ_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteIntObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_EQ_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpEqRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpEqRealObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_NEQ_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpNeqRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpNeqRealObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LT_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLtRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLtRealObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_LTE_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpLteRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpLteRealObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GT_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGtRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGtRealObj(operands[0], operands[1], operands[2]) + } + Opcode.CMP_GTE_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdCmpGteRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdCmpGteRealObj(operands[0], operands[1], operands[2]) + } + Opcode.NOT_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) { + CmdNotBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount) + } else { + CmdNotBool(operands[0], operands[1]) + } + Opcode.AND_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdAndBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdAndBool(operands[0], operands[1], operands[2]) + } + Opcode.OR_BOOL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdOrBoolLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdOrBool(operands[0], operands[1], operands[2]) + } Opcode.CMP_LT_OBJ -> CmdCmpLtObj(operands[0], operands[1], operands[2]) Opcode.CMP_LTE_OBJ -> CmdCmpLteObj(operands[0], operands[1], operands[2]) Opcode.CMP_GT_OBJ -> CmdCmpGtObj(operands[0], operands[1], operands[2]) Opcode.CMP_GTE_OBJ -> CmdCmpGteObj(operands[0], operands[1], operands[2]) + Opcode.ADD_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdAddIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdAddIntObj(operands[0], operands[1], operands[2]) + } + Opcode.SUB_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdSubIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdSubIntObj(operands[0], operands[1], operands[2]) + } + Opcode.MUL_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdMulIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdMulIntObj(operands[0], operands[1], operands[2]) + } + Opcode.DIV_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdDivIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdDivIntObj(operands[0], operands[1], operands[2]) + } + Opcode.MOD_INT_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdModIntObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdModIntObj(operands[0], operands[1], operands[2]) + } + Opcode.ADD_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdAddRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdAddRealObj(operands[0], operands[1], operands[2]) + } + Opcode.SUB_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdSubRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdSubRealObj(operands[0], operands[1], operands[2]) + } + Opcode.MUL_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdMulRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdMulRealObj(operands[0], operands[1], operands[2]) + } + Opcode.DIV_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdDivRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdDivRealObj(operands[0], operands[1], operands[2]) + } + Opcode.MOD_REAL_OBJ -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) { + CmdModRealObjLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount) + } else { + CmdModRealObj(operands[0], operands[1], operands[2]) + } Opcode.ADD_OBJ -> CmdAddObj(operands[0], operands[1], operands[2]) Opcode.SUB_OBJ -> CmdSubObj(operands[0], operands[1], operands[2]) Opcode.MUL_OBJ -> CmdMulObj(operands[0], operands[1], operands[2]) @@ -408,8 +744,16 @@ class CmdBuilder { Opcode.CONTAINS_OBJ -> CmdContainsObj(operands[0], operands[1], operands[2]) Opcode.ASSIGN_OP_OBJ -> CmdAssignOpObj(operands[0], operands[1], operands[2], operands[3], operands[4]) Opcode.JMP -> CmdJmp(operands[0]) - Opcode.JMP_IF_TRUE -> CmdJmpIfTrue(operands[0], operands[1]) - Opcode.JMP_IF_FALSE -> CmdJmpIfFalse(operands[0], operands[1]) + Opcode.JMP_IF_TRUE -> if (operands[0] >= scopeSlotCount) { + CmdJmpIfTrueLocal(operands[0] - scopeSlotCount, operands[1]) + } else { + CmdJmpIfTrue(operands[0], operands[1]) + } + Opcode.JMP_IF_FALSE -> if (operands[0] >= scopeSlotCount) { + CmdJmpIfFalseLocal(operands[0] - scopeSlotCount, operands[1]) + } else { + CmdJmpIfFalse(operands[0], operands[1]) + } Opcode.JMP_IF_EQ_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount) { CmdJmpIfEqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2]) } else { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt index ae36d01..e74c6c1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2026 Sergey S. Chernov + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * */ package net.sergeych.lyng.bytecode @@ -76,6 +77,8 @@ object CmdDisassembler { is CmdMoveObj -> Opcode.MOVE_OBJ to intArrayOf(cmd.src, cmd.dst) is CmdMoveInt -> Opcode.MOVE_INT to intArrayOf(cmd.src, cmd.dst) is CmdMoveIntLocal -> Opcode.MOVE_INT to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) + is CmdMoveRealLocal -> Opcode.MOVE_REAL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) + is CmdMoveBoolLocal -> Opcode.MOVE_BOOL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdMoveReal -> Opcode.MOVE_REAL to intArrayOf(cmd.src, cmd.dst) is CmdMoveBool -> Opcode.MOVE_BOOL to intArrayOf(cmd.src, cmd.dst) is CmdConstObj -> Opcode.CONST_OBJ to intArrayOf(cmd.constId, cmd.dst) @@ -114,9 +117,13 @@ object CmdDisassembler { is CmdLoadBoolAddr -> Opcode.LOAD_BOOL_ADDR to intArrayOf(cmd.addrSlot, cmd.dst) is CmdStoreBoolAddr -> Opcode.STORE_BOOL_ADDR to intArrayOf(cmd.src, cmd.addrSlot) is CmdIntToReal -> Opcode.INT_TO_REAL to intArrayOf(cmd.src, cmd.dst) + is CmdIntToRealLocal -> Opcode.INT_TO_REAL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdRealToInt -> Opcode.REAL_TO_INT to intArrayOf(cmd.src, cmd.dst) + is CmdRealToIntLocal -> Opcode.REAL_TO_INT to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdBoolToInt -> Opcode.BOOL_TO_INT to intArrayOf(cmd.src, cmd.dst) + is CmdBoolToIntLocal -> Opcode.BOOL_TO_INT to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdIntToBool -> Opcode.INT_TO_BOOL to intArrayOf(cmd.src, cmd.dst) + is CmdIntToBoolLocal -> Opcode.INT_TO_BOOL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdAddInt -> Opcode.ADD_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdAddIntLocal -> Opcode.ADD_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdSubInt -> Opcode.SUB_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) @@ -128,22 +135,35 @@ object CmdDisassembler { is CmdModInt -> Opcode.MOD_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdModIntLocal -> Opcode.MOD_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdNegInt -> Opcode.NEG_INT to intArrayOf(cmd.src, cmd.dst) + is CmdNegIntLocal -> Opcode.NEG_INT to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdIncInt -> Opcode.INC_INT to intArrayOf(cmd.slot) is CmdIncIntLocal -> Opcode.INC_INT to intArrayOf(cmd.slot + fn.scopeSlotCount) is CmdDecInt -> Opcode.DEC_INT to intArrayOf(cmd.slot) is CmdDecIntLocal -> Opcode.DEC_INT to intArrayOf(cmd.slot + fn.scopeSlotCount) is CmdAddReal -> Opcode.ADD_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAddRealLocal -> Opcode.ADD_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdSubReal -> Opcode.SUB_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdSubRealLocal -> Opcode.SUB_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdMulReal -> Opcode.MUL_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdMulRealLocal -> Opcode.MUL_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdDivReal -> Opcode.DIV_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdDivRealLocal -> Opcode.DIV_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdNegReal -> Opcode.NEG_REAL to intArrayOf(cmd.src, cmd.dst) + is CmdNegRealLocal -> Opcode.NEG_REAL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdAndInt -> Opcode.AND_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAndIntLocal -> Opcode.AND_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdOrInt -> Opcode.OR_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdOrIntLocal -> Opcode.OR_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdXorInt -> Opcode.XOR_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdXorIntLocal -> Opcode.XOR_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdShlInt -> Opcode.SHL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdShlIntLocal -> Opcode.SHL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdShrInt -> Opcode.SHR_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdShrIntLocal -> Opcode.SHR_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdUshrInt -> Opcode.USHR_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdUshrIntLocal -> Opcode.USHR_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdInvInt -> Opcode.INV_INT to intArrayOf(cmd.src, cmd.dst) + is CmdInvIntLocal -> Opcode.INV_INT to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpEqInt -> Opcode.CMP_EQ_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpEqIntLocal -> Opcode.CMP_EQ_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpNeqInt -> Opcode.CMP_NEQ_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) @@ -157,25 +177,45 @@ object CmdDisassembler { is CmdCmpGteInt -> Opcode.CMP_GTE_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpGteIntLocal -> Opcode.CMP_GTE_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpEqReal -> Opcode.CMP_EQ_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqRealLocal -> Opcode.CMP_EQ_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpNeqReal -> Opcode.CMP_NEQ_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqRealLocal -> Opcode.CMP_NEQ_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLtReal -> Opcode.CMP_LT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtRealLocal -> Opcode.CMP_LT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLteReal -> Opcode.CMP_LTE_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteRealLocal -> Opcode.CMP_LTE_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGtReal -> Opcode.CMP_GT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtRealLocal -> Opcode.CMP_GT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGteReal -> Opcode.CMP_GTE_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteRealLocal -> Opcode.CMP_GTE_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpEqBool -> Opcode.CMP_EQ_BOOL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqBoolLocal -> Opcode.CMP_EQ_BOOL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpNeqBool -> Opcode.CMP_NEQ_BOOL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqBoolLocal -> Opcode.CMP_NEQ_BOOL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpEqIntReal -> Opcode.CMP_EQ_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqIntRealLocal -> Opcode.CMP_EQ_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpEqRealInt -> Opcode.CMP_EQ_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqRealIntLocal -> Opcode.CMP_EQ_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLtIntReal -> Opcode.CMP_LT_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtIntRealLocal -> Opcode.CMP_LT_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLtRealInt -> Opcode.CMP_LT_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtRealIntLocal -> Opcode.CMP_LT_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLteIntReal -> Opcode.CMP_LTE_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteIntRealLocal -> Opcode.CMP_LTE_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpLteRealInt -> Opcode.CMP_LTE_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteRealIntLocal -> Opcode.CMP_LTE_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGtIntReal -> Opcode.CMP_GT_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtIntRealLocal -> Opcode.CMP_GT_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGtRealInt -> Opcode.CMP_GT_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtRealIntLocal -> Opcode.CMP_GT_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGteIntReal -> Opcode.CMP_GTE_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteIntRealLocal -> Opcode.CMP_GTE_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpGteRealInt -> Opcode.CMP_GTE_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteRealIntLocal -> Opcode.CMP_GTE_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpNeqIntReal -> Opcode.CMP_NEQ_INT_REAL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqIntRealLocal -> Opcode.CMP_NEQ_INT_REAL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdCmpNeqRealInt -> Opcode.CMP_NEQ_REAL_INT to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqRealIntLocal -> Opcode.CMP_NEQ_REAL_INT to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdJmpIfEqInt -> Opcode.JMP_IF_EQ_INT to intArrayOf(cmd.a, cmd.b, cmd.target) is CmdJmpIfEqIntLocal -> Opcode.JMP_IF_EQ_INT to intArrayOf( cmd.a + fn.scopeSlotCount, @@ -216,13 +256,194 @@ object CmdDisassembler { is CmdCmpNeqObj -> Opcode.CMP_NEQ_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpRefEqObj -> Opcode.CMP_REF_EQ_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpRefNeqObj -> Opcode.CMP_REF_NEQ_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqStr -> Opcode.CMP_EQ_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqStrLocal -> Opcode.CMP_EQ_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpNeqStr -> Opcode.CMP_NEQ_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqStrLocal -> Opcode.CMP_NEQ_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLtStr -> Opcode.CMP_LT_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtStrLocal -> Opcode.CMP_LT_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLteStr -> Opcode.CMP_LTE_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteStrLocal -> Opcode.CMP_LTE_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGtStr -> Opcode.CMP_GT_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtStrLocal -> Opcode.CMP_GT_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGteStr -> Opcode.CMP_GTE_STR to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteStrLocal -> Opcode.CMP_GTE_STR to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpEqIntObj -> Opcode.CMP_EQ_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqIntObjLocal -> Opcode.CMP_EQ_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpNeqIntObj -> Opcode.CMP_NEQ_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqIntObjLocal -> Opcode.CMP_NEQ_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLtIntObj -> Opcode.CMP_LT_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtIntObjLocal -> Opcode.CMP_LT_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLteIntObj -> Opcode.CMP_LTE_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteIntObjLocal -> Opcode.CMP_LTE_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGtIntObj -> Opcode.CMP_GT_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtIntObjLocal -> Opcode.CMP_GT_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGteIntObj -> Opcode.CMP_GTE_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteIntObjLocal -> Opcode.CMP_GTE_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpEqRealObj -> Opcode.CMP_EQ_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpEqRealObjLocal -> Opcode.CMP_EQ_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpNeqRealObj -> Opcode.CMP_NEQ_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpNeqRealObjLocal -> Opcode.CMP_NEQ_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLtRealObj -> Opcode.CMP_LT_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLtRealObjLocal -> Opcode.CMP_LT_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpLteRealObj -> Opcode.CMP_LTE_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpLteRealObjLocal -> Opcode.CMP_LTE_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGtRealObj -> Opcode.CMP_GT_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGtRealObjLocal -> Opcode.CMP_GT_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdCmpGteRealObj -> Opcode.CMP_GTE_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdCmpGteRealObjLocal -> Opcode.CMP_GTE_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) is CmdNotBool -> Opcode.NOT_BOOL to intArrayOf(cmd.src, cmd.dst) + is CmdNotBoolLocal -> Opcode.NOT_BOOL to intArrayOf(cmd.src + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdAndBool -> Opcode.AND_BOOL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAndBoolLocal -> Opcode.AND_BOOL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) is CmdOrBool -> Opcode.OR_BOOL to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdOrBoolLocal -> Opcode.OR_BOOL to intArrayOf(cmd.a + fn.scopeSlotCount, cmd.b + fn.scopeSlotCount, cmd.dst + fn.scopeSlotCount) + is CmdUnboxIntObj -> Opcode.UNBOX_INT_OBJ to intArrayOf(cmd.src, cmd.dst) + is CmdUnboxIntObjLocal -> Opcode.UNBOX_INT_OBJ to intArrayOf( + cmd.src + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdUnboxRealObj -> Opcode.UNBOX_REAL_OBJ to intArrayOf(cmd.src, cmd.dst) + is CmdUnboxRealObjLocal -> Opcode.UNBOX_REAL_OBJ to intArrayOf( + cmd.src + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) is CmdCmpLtObj -> Opcode.CMP_LT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpLteObj -> Opcode.CMP_LTE_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpGtObj -> Opcode.CMP_GT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdCmpGteObj -> Opcode.CMP_GTE_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAddIntObj -> Opcode.ADD_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAddIntObjLocal -> Opcode.ADD_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdSubIntObj -> Opcode.SUB_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdSubIntObjLocal -> Opcode.SUB_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdMulIntObj -> Opcode.MUL_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdMulIntObjLocal -> Opcode.MUL_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdDivIntObj -> Opcode.DIV_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdDivIntObjLocal -> Opcode.DIV_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdModIntObj -> Opcode.MOD_INT_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdModIntObjLocal -> Opcode.MOD_INT_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdAddRealObj -> Opcode.ADD_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdAddRealObjLocal -> Opcode.ADD_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdSubRealObj -> Opcode.SUB_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdSubRealObjLocal -> Opcode.SUB_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdMulRealObj -> Opcode.MUL_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdMulRealObjLocal -> Opcode.MUL_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdDivRealObj -> Opcode.DIV_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdDivRealObjLocal -> Opcode.DIV_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) + is CmdModRealObj -> Opcode.MOD_REAL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) + is CmdModRealObjLocal -> Opcode.MOD_REAL_OBJ to intArrayOf( + cmd.a + fn.scopeSlotCount, + cmd.b + fn.scopeSlotCount, + cmd.dst + fn.scopeSlotCount + ) is CmdAddObj -> Opcode.ADD_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdSubObj -> Opcode.SUB_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) is CmdMulObj -> Opcode.MUL_OBJ to intArrayOf(cmd.a, cmd.b, cmd.dst) @@ -232,7 +453,9 @@ object CmdDisassembler { is CmdAssignOpObj -> Opcode.ASSIGN_OP_OBJ to intArrayOf(cmd.opId, cmd.targetSlot, cmd.valueSlot, cmd.dst, cmd.nameId) is CmdJmp -> Opcode.JMP to intArrayOf(cmd.target) is CmdJmpIfTrue -> Opcode.JMP_IF_TRUE to intArrayOf(cmd.cond, cmd.target) + is CmdJmpIfTrueLocal -> Opcode.JMP_IF_TRUE to intArrayOf(cmd.cond + fn.scopeSlotCount, cmd.target) is CmdJmpIfFalse -> Opcode.JMP_IF_FALSE to intArrayOf(cmd.cond, cmd.target) + is CmdJmpIfFalseLocal -> Opcode.JMP_IF_FALSE to intArrayOf(cmd.cond + fn.scopeSlotCount, cmd.target) is CmdRet -> Opcode.RET to intArrayOf(cmd.slot) is CmdRetLabel -> Opcode.RET_LABEL to intArrayOf(cmd.labelId, cmd.slot) is CmdRetVoid -> Opcode.RET_VOID to intArrayOf() @@ -298,6 +521,7 @@ object CmdDisassembler { Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING, Opcode.ITER_POP, Opcode.ITER_CANCEL -> emptyList() Opcode.MOVE_OBJ, Opcode.MOVE_INT, Opcode.MOVE_REAL, Opcode.MOVE_BOOL, Opcode.BOX_OBJ, + Opcode.UNBOX_INT_OBJ, Opcode.UNBOX_REAL_OBJ, 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 -> listOf(OperandKind.SLOT, OperandKind.SLOT) @@ -351,7 +575,14 @@ object CmdDisassembler { Opcode.CMP_LTE_INT_REAL, Opcode.CMP_LTE_REAL_INT, Opcode.CMP_GT_INT_REAL, Opcode.CMP_GT_REAL_INT, Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT, Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ, + Opcode.CMP_EQ_STR, Opcode.CMP_NEQ_STR, Opcode.CMP_LT_STR, Opcode.CMP_LTE_STR, + Opcode.CMP_GT_STR, Opcode.CMP_GTE_STR, + Opcode.CMP_EQ_INT_OBJ, Opcode.CMP_NEQ_INT_OBJ, Opcode.CMP_LT_INT_OBJ, Opcode.CMP_LTE_INT_OBJ, + Opcode.CMP_GT_INT_OBJ, Opcode.CMP_GTE_INT_OBJ, Opcode.CMP_EQ_REAL_OBJ, Opcode.CMP_NEQ_REAL_OBJ, + Opcode.CMP_LT_REAL_OBJ, Opcode.CMP_LTE_REAL_OBJ, Opcode.CMP_GT_REAL_OBJ, Opcode.CMP_GTE_REAL_OBJ, Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ, + Opcode.ADD_INT_OBJ, Opcode.SUB_INT_OBJ, Opcode.MUL_INT_OBJ, Opcode.DIV_INT_OBJ, Opcode.MOD_INT_OBJ, + Opcode.ADD_REAL_OBJ, Opcode.SUB_REAL_OBJ, Opcode.MUL_REAL_OBJ, Opcode.DIV_REAL_OBJ, Opcode.MOD_REAL_OBJ, Opcode.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ, Opcode.AND_BOOL, Opcode.OR_BOOL -> listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt index fb8fc90..5a16616 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -40,7 +40,11 @@ class CmdVm { while (result == null) { val cmd = cmds[frame.ip] frame.ip += 1 - cmd.perform(frame) + if (cmd.isFast) { + cmd.performFast(frame) + } else { + cmd.perform(frame) + } } } catch (e: Throwable) { if (!frame.handleException(e)) { @@ -63,7 +67,13 @@ class CmdVm { } sealed class Cmd { - abstract suspend fun perform(frame: CmdFrame) + open val isFast: Boolean = false + open fun performFast(frame: CmdFrame) { + error("fast command not supported: ${this::class.simpleName}") + } + open suspend fun perform(frame: CmdFrame) { + error("slow command not supported: ${this::class.simpleName}") + } } class CmdNop : Cmd() { @@ -97,7 +107,8 @@ class CmdMoveInt(internal val src: Int, internal val dst: Int) : Cmd() { } class CmdMoveIntLocal(internal val src: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(src)) return } @@ -115,6 +126,14 @@ class CmdMoveReal(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdMoveRealLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, frame.getLocalReal(src)) + return + } +} + class CmdMoveBool(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { val value = frame.getBool(src) @@ -127,8 +146,17 @@ class CmdMoveBool(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdMoveBoolLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalBool(src)) + return + } +} + class CmdConstObj(internal val constId: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { when (val c = frame.fn.constants[constId]) { is BytecodeConst.ObjRef -> { val obj = c.value @@ -147,7 +175,8 @@ class CmdConstObj(internal val constId: Int, internal val dst: Int) : Cmd() { } class CmdConstInt(internal val constId: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { val c = frame.fn.constants[constId] as? BytecodeConst.IntVal ?: error("CONST_INT expects IntVal at $constId") frame.setInt(dst, c.value) @@ -156,7 +185,8 @@ class CmdConstInt(internal val constId: Int, internal val dst: Int) : Cmd() { } class CmdConstIntLocal(internal val constId: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { val c = frame.fn.constants[constId] as? BytecodeConst.IntVal ?: error("CONST_INT expects IntVal at $constId") frame.setLocalInt(dst, c.value) @@ -165,7 +195,8 @@ class CmdConstIntLocal(internal val constId: Int, internal val dst: Int) : Cmd() } class CmdConstReal(internal val constId: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { val c = frame.fn.constants[constId] as? BytecodeConst.RealVal ?: error("CONST_REAL expects RealVal at $constId") frame.setReal(dst, c.value) @@ -174,7 +205,8 @@ class CmdConstReal(internal val constId: Int, internal val dst: Int) : Cmd() { } class CmdConstBool(internal val constId: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { val c = frame.fn.constants[constId] as? BytecodeConst.Bool ?: error("CONST_BOOL expects Bool at $constId") frame.setBool(dst, c.value) @@ -236,6 +268,40 @@ class CmdBoxObj(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdUnboxIntObj(internal val src: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val value = frame.slotToObj(src) as ObjInt + frame.setInt(dst, value.value) + return + } +} + +class CmdUnboxIntObjLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val value = frame.frame.getRawObj(src) as ObjInt + frame.setLocalInt(dst, value.value) + return + } +} + +class CmdUnboxRealObj(internal val src: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val value = frame.slotToObj(src) as ObjReal + frame.setReal(dst, value.value) + return + } +} + +class CmdUnboxRealObjLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val value = frame.frame.getRawObj(src) as ObjReal + frame.setLocalReal(dst, value.value) + return + } +} + class CmdObjToBool(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.slotToObj(src).toBool()) @@ -500,6 +566,15 @@ class CmdIntToReal(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdIntToRealLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val value = frame.getLocalObjRealValue(src) + frame.setLocalReal(dst, value) + return + } +} + class CmdRealToInt(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getReal(src).toLong()) @@ -507,6 +582,14 @@ class CmdRealToInt(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdRealToIntLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalReal(src).toLong()) + return + } +} + class CmdBoolToInt(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, if (frame.getBool(src)) 1L else 0L) @@ -514,6 +597,14 @@ class CmdBoolToInt(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdBoolToIntLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, if (frame.getLocalBool(src)) 1L else 0L) + return + } +} + class CmdIntToBool(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getBool(src)) @@ -521,6 +612,14 @@ class CmdIntToBool(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdIntToBoolLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(src) != 0L) + return + } +} + class CmdAddInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) + frame.getInt(b)) @@ -529,7 +628,8 @@ class CmdAddInt(internal val a: Int, internal val b: Int, internal val dst: Int) } class CmdAddIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(a) + frame.getLocalInt(b)) return } @@ -543,7 +643,8 @@ class CmdSubInt(internal val a: Int, internal val b: Int, internal val dst: Int) } class CmdSubIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(a) - frame.getLocalInt(b)) return } @@ -557,7 +658,8 @@ class CmdMulInt(internal val a: Int, internal val b: Int, internal val dst: Int) } class CmdMulIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(a) * frame.getLocalInt(b)) return } @@ -571,7 +673,8 @@ class CmdDivInt(internal val a: Int, internal val b: Int, internal val dst: Int) } class CmdDivIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(a) / frame.getLocalInt(b)) return } @@ -585,7 +688,8 @@ class CmdModInt(internal val a: Int, internal val b: Int, internal val dst: Int) } class CmdModIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(dst, frame.getLocalInt(a) % frame.getLocalInt(b)) return } @@ -598,6 +702,14 @@ class CmdNegInt(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdNegIntLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, -frame.getLocalInt(src)) + return + } +} + class CmdIncInt(internal val slot: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(slot, frame.getInt(slot) + 1L) @@ -606,7 +718,8 @@ class CmdIncInt(internal val slot: Int) : Cmd() { } class CmdIncIntLocal(internal val slot: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(slot, frame.getLocalInt(slot) + 1L) return } @@ -620,7 +733,8 @@ class CmdDecInt(internal val slot: Int) : Cmd() { } class CmdDecIntLocal(internal val slot: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalInt(slot, frame.getLocalInt(slot) - 1L) return } @@ -633,6 +747,14 @@ class CmdAddReal(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdAddRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, frame.getLocalReal(a) + frame.getLocalReal(b)) + return + } +} + class CmdSubReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setReal(dst, frame.getReal(a) - frame.getReal(b)) @@ -640,6 +762,14 @@ class CmdSubReal(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdSubRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, frame.getLocalReal(a) - frame.getLocalReal(b)) + return + } +} + class CmdMulReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setReal(dst, frame.getReal(a) * frame.getReal(b)) @@ -647,6 +777,14 @@ class CmdMulReal(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdMulRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, frame.getLocalReal(a) * frame.getLocalReal(b)) + return + } +} + class CmdDivReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setReal(dst, frame.getReal(a) / frame.getReal(b)) @@ -654,6 +792,14 @@ class CmdDivReal(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdDivRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, frame.getLocalReal(a) / frame.getLocalReal(b)) + return + } +} + class CmdNegReal(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setReal(dst, -frame.getReal(src)) @@ -661,6 +807,14 @@ class CmdNegReal(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdNegRealLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalReal(dst, -frame.getLocalReal(src)) + return + } +} + class CmdAndInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) and frame.getInt(b)) @@ -668,6 +822,14 @@ class CmdAndInt(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdAndIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) and frame.getLocalInt(b)) + return + } +} + class CmdOrInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) or frame.getInt(b)) @@ -675,6 +837,14 @@ class CmdOrInt(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdOrIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) or frame.getLocalInt(b)) + return + } +} + class CmdXorInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) xor frame.getInt(b)) @@ -682,6 +852,14 @@ class CmdXorInt(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdXorIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) xor frame.getLocalInt(b)) + return + } +} + class CmdShlInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) shl frame.getInt(b).toInt()) @@ -689,6 +867,14 @@ class CmdShlInt(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdShlIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) shl frame.getLocalInt(b).toInt()) + return + } +} + class CmdShrInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) shr frame.getInt(b).toInt()) @@ -696,6 +882,14 @@ class CmdShrInt(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdShrIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) shr frame.getLocalInt(b).toInt()) + return + } +} + class CmdUshrInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(a) ushr frame.getInt(b).toInt()) @@ -703,6 +897,14 @@ class CmdUshrInt(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdUshrIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(a) ushr frame.getLocalInt(b).toInt()) + return + } +} + class CmdInvInt(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setInt(dst, frame.getInt(src).inv()) @@ -710,6 +912,13 @@ class CmdInvInt(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdInvIntLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalInt(dst, frame.getLocalInt(src).inv()) + return + } +} class CmdCmpEqInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a) == frame.getInt(b)) @@ -718,7 +927,8 @@ class CmdCmpEqInt(internal val a: Int, internal val b: Int, internal val dst: In } class CmdCmpEqIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) == frame.getLocalInt(b)) return } @@ -732,7 +942,8 @@ class CmdCmpNeqInt(internal val a: Int, internal val b: Int, internal val dst: I } class CmdCmpNeqIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) != frame.getLocalInt(b)) return } @@ -746,7 +957,8 @@ class CmdCmpLtInt(internal val a: Int, internal val b: Int, internal val dst: In } class CmdCmpLtIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) < frame.getLocalInt(b)) return } @@ -760,7 +972,8 @@ class CmdCmpLteInt(internal val a: Int, internal val b: Int, internal val dst: I } class CmdCmpLteIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) <= frame.getLocalInt(b)) return } @@ -774,7 +987,8 @@ class CmdCmpGtInt(internal val a: Int, internal val b: Int, internal val dst: In } class CmdCmpGtIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) > frame.getLocalInt(b)) return } @@ -788,7 +1002,8 @@ class CmdCmpGteInt(internal val a: Int, internal val b: Int, internal val dst: I } class CmdCmpGteIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.setLocalBool(dst, frame.getLocalInt(a) >= frame.getLocalInt(b)) return } @@ -801,6 +1016,14 @@ class CmdCmpEqReal(internal val a: Int, internal val b: Int, internal val dst: I } } +class CmdCmpEqRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) == frame.getLocalReal(b)) + return + } +} + class CmdCmpNeqReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) != frame.getReal(b)) @@ -808,6 +1031,14 @@ class CmdCmpNeqReal(internal val a: Int, internal val b: Int, internal val dst: } } +class CmdCmpNeqRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) != frame.getLocalReal(b)) + return + } +} + class CmdCmpLtReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) < frame.getReal(b)) @@ -815,6 +1046,14 @@ class CmdCmpLtReal(internal val a: Int, internal val b: Int, internal val dst: I } } +class CmdCmpLtRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) < frame.getLocalReal(b)) + return + } +} + class CmdCmpLteReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) <= frame.getReal(b)) @@ -822,6 +1061,14 @@ class CmdCmpLteReal(internal val a: Int, internal val b: Int, internal val dst: } } +class CmdCmpLteRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) <= frame.getLocalReal(b)) + return + } +} + class CmdCmpGtReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) > frame.getReal(b)) @@ -829,6 +1076,14 @@ class CmdCmpGtReal(internal val a: Int, internal val b: Int, internal val dst: I } } +class CmdCmpGtRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) > frame.getLocalReal(b)) + return + } +} + class CmdCmpGteReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) >= frame.getReal(b)) @@ -836,6 +1091,14 @@ class CmdCmpGteReal(internal val a: Int, internal val b: Int, internal val dst: } } +class CmdCmpGteRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) >= frame.getLocalReal(b)) + return + } +} + class CmdCmpEqBool(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getBool(a) == frame.getBool(b)) @@ -843,6 +1106,14 @@ class CmdCmpEqBool(internal val a: Int, internal val b: Int, internal val dst: I } } +class CmdCmpEqBoolLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalBool(a) == frame.getLocalBool(b)) + return + } +} + class CmdCmpNeqBool(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getBool(a) != frame.getBool(b)) @@ -850,6 +1121,14 @@ class CmdCmpNeqBool(internal val a: Int, internal val b: Int, internal val dst: } } +class CmdCmpNeqBoolLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalBool(a) != frame.getLocalBool(b)) + return + } +} + class CmdCmpEqIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() == frame.getReal(b)) @@ -857,6 +1136,14 @@ class CmdCmpEqIntReal(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpEqIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() == frame.getLocalReal(b)) + return + } +} + class CmdCmpEqRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) == frame.getInt(b).toDouble()) @@ -864,6 +1151,14 @@ class CmdCmpEqRealInt(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpEqRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) == frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpLtIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() < frame.getReal(b)) @@ -871,6 +1166,14 @@ class CmdCmpLtIntReal(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpLtIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() < frame.getLocalReal(b)) + return + } +} + class CmdCmpLtRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) < frame.getInt(b).toDouble()) @@ -878,6 +1181,14 @@ class CmdCmpLtRealInt(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpLtRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) < frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpLteIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() <= frame.getReal(b)) @@ -885,6 +1196,14 @@ class CmdCmpLteIntReal(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpLteIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() <= frame.getLocalReal(b)) + return + } +} + class CmdCmpLteRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) <= frame.getInt(b).toDouble()) @@ -892,6 +1211,14 @@ class CmdCmpLteRealInt(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpLteRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) <= frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpGtIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() > frame.getReal(b)) @@ -899,6 +1226,14 @@ class CmdCmpGtIntReal(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpGtIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() > frame.getLocalReal(b)) + return + } +} + class CmdCmpGtRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) > frame.getInt(b).toDouble()) @@ -906,6 +1241,14 @@ class CmdCmpGtRealInt(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpGtRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) > frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpGteIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() >= frame.getReal(b)) @@ -913,6 +1256,14 @@ class CmdCmpGteIntReal(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpGteIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() >= frame.getLocalReal(b)) + return + } +} + class CmdCmpGteRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) >= frame.getInt(b).toDouble()) @@ -920,6 +1271,14 @@ class CmdCmpGteRealInt(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpGteRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) >= frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpNeqIntReal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getInt(a).toDouble() != frame.getReal(b)) @@ -927,6 +1286,14 @@ class CmdCmpNeqIntReal(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpNeqIntRealLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalInt(a).toDouble() != frame.getLocalReal(b)) + return + } +} + class CmdCmpNeqRealInt(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getReal(a) != frame.getInt(b).toDouble()) @@ -934,6 +1301,14 @@ class CmdCmpNeqRealInt(internal val a: Int, internal val b: Int, internal val ds } } +class CmdCmpNeqRealIntLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalReal(a) != frame.getLocalInt(b).toDouble()) + return + } +} + class CmdCmpEqObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { val left = frame.slotToObj(a) @@ -966,6 +1341,420 @@ class CmdCmpRefNeqObj(internal val a: Int, internal val b: Int, internal val dst } } +class CmdCmpEqStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value == right.value) + return + } + frame.setBool(dst, left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpEqStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value == right.value) + return + } +} + +class CmdCmpNeqStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value != right.value) + return + } + frame.setBool(dst, !left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpNeqStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value != right.value) + return + } +} + +class CmdCmpLtStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value < right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) < 0) + return + } +} + +class CmdCmpLtStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value < right.value) + return + } +} + +class CmdCmpLteStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value <= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) <= 0) + return + } +} + +class CmdCmpLteStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value <= right.value) + return + } +} + +class CmdCmpGtStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value > right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) > 0) + return + } +} + +class CmdCmpGtStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value > right.value) + return + } +} + +class CmdCmpGteStr(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjString && right is ObjString) { + frame.setBool(dst, left.value >= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) >= 0) + return + } +} + +class CmdCmpGteStrLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjString + val right = frame.frame.getRawObj(b) as ObjString + frame.setLocalBool(dst, left.value >= right.value) + return + } +} + +class CmdCmpEqIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value == right.value) + return + } + frame.setBool(dst, left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpEqIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value == right.value) + return + } +} + +class CmdCmpNeqIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value != right.value) + return + } + frame.setBool(dst, !left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpNeqIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value != right.value) + return + } +} + +class CmdCmpLtIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value < right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) < 0) + return + } +} + +class CmdCmpLtIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value < right.value) + return + } +} + +class CmdCmpLteIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value <= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) <= 0) + return + } +} + +class CmdCmpLteIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value <= right.value) + return + } +} + +class CmdCmpGtIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value > right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) > 0) + return + } +} + +class CmdCmpGtIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value > right.value) + return + } +} + +class CmdCmpGteIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjInt && right is ObjInt) { + frame.setBool(dst, left.value >= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) >= 0) + return + } +} + +class CmdCmpGteIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjInt + val right = frame.frame.getRawObj(b) as ObjInt + frame.setLocalBool(dst, left.value >= right.value) + return + } +} + +class CmdCmpEqRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value == right.value) + return + } + frame.setBool(dst, left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpEqRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value == right.value) + return + } +} + +class CmdCmpNeqRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value != right.value) + return + } + frame.setBool(dst, !left.equals(frame.ensureScope(), right)) + return + } +} + +class CmdCmpNeqRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value != right.value) + return + } +} + +class CmdCmpLtRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value < right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) < 0) + return + } +} + +class CmdCmpLtRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value < right.value) + return + } +} + +class CmdCmpLteRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value <= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) <= 0) + return + } +} + +class CmdCmpLteRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value <= right.value) + return + } +} + +class CmdCmpGtRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value > right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) > 0) + return + } +} + +class CmdCmpGtRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value > right.value) + return + } +} + +class CmdCmpGteRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) + val right = frame.slotToObj(b) + if (left is ObjReal && right is ObjReal) { + frame.setBool(dst, left.value >= right.value) + return + } + frame.setBool(dst, left.compareTo(frame.ensureScope(), right) >= 0) + return + } +} + +class CmdCmpGteRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.frame.getRawObj(a) as ObjReal + val right = frame.frame.getRawObj(b) as ObjReal + frame.setLocalBool(dst, left.value >= right.value) + return + } +} + class CmdNotBool(internal val src: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, !frame.getBool(src)) @@ -973,6 +1762,14 @@ class CmdNotBool(internal val src: Int, internal val dst: Int) : Cmd() { } } +class CmdNotBoolLocal(internal val src: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, !frame.getLocalBool(src)) + return + } +} + class CmdAndBool(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getBool(a) && frame.getBool(b)) @@ -980,6 +1777,14 @@ class CmdAndBool(internal val a: Int, internal val b: Int, internal val dst: Int } } +class CmdAndBoolLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalBool(a) && frame.getLocalBool(b)) + return + } +} + class CmdOrBool(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.getBool(a) || frame.getBool(b)) @@ -987,6 +1792,14 @@ class CmdOrBool(internal val a: Int, internal val b: Int, internal val dst: Int) } } +class CmdOrBoolLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + frame.setLocalBool(dst, frame.getLocalBool(a) || frame.getLocalBool(b)) + return + } +} + class CmdCmpLtObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { frame.setBool(dst, frame.slotToObj(a).compareTo(frame.ensureScope(), frame.slotToObj(b)) < 0) @@ -1017,215 +1830,230 @@ class CmdCmpGteObj(internal val a: Int, internal val b: Int, internal val dst: I class CmdAddObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { - val scopeSlotCount = frame.fn.scopeSlotCount - if (a >= scopeSlotCount && b >= scopeSlotCount) { - val la = a - scopeSlotCount - val lb = b - scopeSlotCount - val ta = frame.frame.getSlotTypeCode(la) - val tb = frame.frame.getSlotTypeCode(lb) - if (ta == SlotType.INT.code && tb == SlotType.INT.code) { - frame.setInt(dst, frame.frame.getInt(la) + frame.frame.getInt(lb)) - return - } - val aNumeric = ta == SlotType.INT.code || ta == SlotType.REAL.code - val bNumeric = tb == SlotType.INT.code || tb == SlotType.REAL.code - if (aNumeric && bNumeric && (ta == SlotType.REAL.code || tb == SlotType.REAL.code)) { - val av = if (ta == SlotType.REAL.code) frame.frame.getReal(la) else frame.frame.getInt(la).toDouble() - val bv = if (tb == SlotType.REAL.code) frame.frame.getReal(lb) else frame.frame.getInt(lb).toDouble() - frame.setReal(dst, av + bv) - return - } - } - val left = frame.slotToObj(a) - val right = frame.slotToObj(b) - if (left is ObjInt && right is ObjInt) { - frame.setInt(dst, left.value + right.value) - return - } - if ((left is ObjInt || left is ObjReal) && (right is ObjInt || right is ObjReal)) { - val av = if (left is ObjReal) left.value else (left as ObjInt).value.toDouble() - val bv = if (right is ObjReal) right.value else (right as ObjInt).value.toDouble() - frame.setReal(dst, av + bv) - return - } - val result = left.plus(frame.ensureScope(), right) - when (result) { - is ObjInt -> frame.setInt(dst, result.value) - is ObjReal -> frame.setReal(dst, result.value) - else -> frame.setObj(dst, result) - } + val result = frame.slotToObj(a).plus(frame.ensureScope(), frame.slotToObj(b)) + frame.storeObjResult(dst, result) return } } class CmdSubObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { - val scopeSlotCount = frame.fn.scopeSlotCount - if (a >= scopeSlotCount && b >= scopeSlotCount) { - val la = a - scopeSlotCount - val lb = b - scopeSlotCount - val ta = frame.frame.getSlotTypeCode(la) - val tb = frame.frame.getSlotTypeCode(lb) - if (ta == SlotType.INT.code && tb == SlotType.INT.code) { - frame.setInt(dst, frame.frame.getInt(la) - frame.frame.getInt(lb)) - return - } - val aNumeric = ta == SlotType.INT.code || ta == SlotType.REAL.code - val bNumeric = tb == SlotType.INT.code || tb == SlotType.REAL.code - if (aNumeric && bNumeric && (ta == SlotType.REAL.code || tb == SlotType.REAL.code)) { - val av = if (ta == SlotType.REAL.code) frame.frame.getReal(la) else frame.frame.getInt(la).toDouble() - val bv = if (tb == SlotType.REAL.code) frame.frame.getReal(lb) else frame.frame.getInt(lb).toDouble() - frame.setReal(dst, av - bv) - return - } - } - val left = frame.slotToObj(a) - val right = frame.slotToObj(b) - if (left is ObjInt && right is ObjInt) { - frame.setInt(dst, left.value - right.value) - return - } - if ((left is ObjInt || left is ObjReal) && (right is ObjInt || right is ObjReal)) { - val av = if (left is ObjReal) left.value else (left as ObjInt).value.toDouble() - val bv = if (right is ObjReal) right.value else (right as ObjInt).value.toDouble() - frame.setReal(dst, av - bv) - return - } - val result = left.minus(frame.ensureScope(), right) - when (result) { - is ObjInt -> frame.setInt(dst, result.value) - is ObjReal -> frame.setReal(dst, result.value) - else -> frame.setObj(dst, result) - } + val result = frame.slotToObj(a).minus(frame.ensureScope(), frame.slotToObj(b)) + frame.storeObjResult(dst, result) return } } class CmdMulObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { - val scopeSlotCount = frame.fn.scopeSlotCount - if (a >= scopeSlotCount && b >= scopeSlotCount) { - val la = a - scopeSlotCount - val lb = b - scopeSlotCount - val ta = frame.frame.getSlotTypeCode(la) - val tb = frame.frame.getSlotTypeCode(lb) - if (ta == SlotType.INT.code && tb == SlotType.INT.code) { - frame.setInt(dst, frame.frame.getInt(la) * frame.frame.getInt(lb)) - return - } - val aNumeric = ta == SlotType.INT.code || ta == SlotType.REAL.code - val bNumeric = tb == SlotType.INT.code || tb == SlotType.REAL.code - if (aNumeric && bNumeric && (ta == SlotType.REAL.code || tb == SlotType.REAL.code)) { - val av = if (ta == SlotType.REAL.code) frame.frame.getReal(la) else frame.frame.getInt(la).toDouble() - val bv = if (tb == SlotType.REAL.code) frame.frame.getReal(lb) else frame.frame.getInt(lb).toDouble() - frame.setReal(dst, av * bv) - return - } - } - val left = frame.slotToObj(a) - val right = frame.slotToObj(b) - if (left is ObjInt && right is ObjInt) { - frame.setInt(dst, left.value * right.value) - return - } - if ((left is ObjInt || left is ObjReal) && (right is ObjInt || right is ObjReal)) { - val av = if (left is ObjReal) left.value else (left as ObjInt).value.toDouble() - val bv = if (right is ObjReal) right.value else (right as ObjInt).value.toDouble() - frame.setReal(dst, av * bv) - return - } - val result = left.mul(frame.ensureScope(), right) - when (result) { - is ObjInt -> frame.setInt(dst, result.value) - is ObjReal -> frame.setReal(dst, result.value) - else -> frame.setObj(dst, result) - } + val result = frame.slotToObj(a).mul(frame.ensureScope(), frame.slotToObj(b)) + frame.storeObjResult(dst, result) return } } class CmdDivObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { - val scopeSlotCount = frame.fn.scopeSlotCount - if (a >= scopeSlotCount && b >= scopeSlotCount) { - val la = a - scopeSlotCount - val lb = b - scopeSlotCount - val ta = frame.frame.getSlotTypeCode(la) - val tb = frame.frame.getSlotTypeCode(lb) - if (ta == SlotType.INT.code && tb == SlotType.INT.code) { - frame.setInt(dst, frame.frame.getInt(la) / frame.frame.getInt(lb)) - return - } - val aNumeric = ta == SlotType.INT.code || ta == SlotType.REAL.code - val bNumeric = tb == SlotType.INT.code || tb == SlotType.REAL.code - if (aNumeric && bNumeric && (ta == SlotType.REAL.code || tb == SlotType.REAL.code)) { - val av = if (ta == SlotType.REAL.code) frame.frame.getReal(la) else frame.frame.getInt(la).toDouble() - val bv = if (tb == SlotType.REAL.code) frame.frame.getReal(lb) else frame.frame.getInt(lb).toDouble() - frame.setReal(dst, av / bv) - return - } - } - val left = frame.slotToObj(a) - val right = frame.slotToObj(b) - if (left is ObjInt && right is ObjInt) { - frame.setInt(dst, left.value / right.value) - return - } - if ((left is ObjInt || left is ObjReal) && (right is ObjInt || right is ObjReal)) { - val av = if (left is ObjReal) left.value else (left as ObjInt).value.toDouble() - val bv = if (right is ObjReal) right.value else (right as ObjInt).value.toDouble() - frame.setReal(dst, av / bv) - return - } - val result = left.div(frame.ensureScope(), right) - when (result) { - is ObjInt -> frame.setInt(dst, result.value) - is ObjReal -> frame.setReal(dst, result.value) - else -> frame.setObj(dst, result) - } + val result = frame.slotToObj(a).div(frame.ensureScope(), frame.slotToObj(b)) + frame.storeObjResult(dst, result) return } } class CmdModObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { - val scopeSlotCount = frame.fn.scopeSlotCount - if (a >= scopeSlotCount && b >= scopeSlotCount) { - val la = a - scopeSlotCount - val lb = b - scopeSlotCount - val ta = frame.frame.getSlotTypeCode(la) - val tb = frame.frame.getSlotTypeCode(lb) - if (ta == SlotType.INT.code && tb == SlotType.INT.code) { - frame.setInt(dst, frame.frame.getInt(la) % frame.frame.getInt(lb)) - return - } - val aNumeric = ta == SlotType.INT.code || ta == SlotType.REAL.code - val bNumeric = tb == SlotType.INT.code || tb == SlotType.REAL.code - if (aNumeric && bNumeric && (ta == SlotType.REAL.code || tb == SlotType.REAL.code)) { - val av = if (ta == SlotType.REAL.code) frame.frame.getReal(la) else frame.frame.getInt(la).toDouble() - val bv = if (tb == SlotType.REAL.code) frame.frame.getReal(lb) else frame.frame.getInt(lb).toDouble() - frame.setReal(dst, av % bv) - return - } - } - val left = frame.slotToObj(a) - val right = frame.slotToObj(b) - if (left is ObjInt && right is ObjInt) { - frame.setInt(dst, left.value % right.value) - return - } - if ((left is ObjInt || left is ObjReal) && (right is ObjInt || right is ObjReal)) { - val av = if (left is ObjReal) left.value else (left as ObjInt).value.toDouble() - val bv = if (right is ObjReal) right.value else (right as ObjInt).value.toDouble() - frame.setReal(dst, av % bv) - return - } - val result = left.mod(frame.ensureScope(), right) - when (result) { - is ObjInt -> frame.setInt(dst, result.value) - is ObjReal -> frame.setReal(dst, result.value) - else -> frame.setObj(dst, result) - } + val result = frame.slotToObj(a).mod(frame.ensureScope(), frame.slotToObj(b)) + frame.storeObjResult(dst, result) + return + } +} + +class CmdAddIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjInt + val right = frame.slotToObj(b) as ObjInt + frame.storeObjResult(dst, ObjInt.of(left.value + right.value)) + return + } +} + +class CmdAddIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjIntValue(a) + val right = frame.getLocalObjIntValue(b) + frame.storeObjResult(dst, ObjInt.of(left + right)) + return + } +} + +class CmdSubIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjInt + val right = frame.slotToObj(b) as ObjInt + frame.storeObjResult(dst, ObjInt.of(left.value - right.value)) + return + } +} + +class CmdSubIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjIntValue(a) + val right = frame.getLocalObjIntValue(b) + frame.storeObjResult(dst, ObjInt.of(left - right)) + return + } +} + +class CmdMulIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjInt + val right = frame.slotToObj(b) as ObjInt + frame.storeObjResult(dst, ObjInt.of(left.value * right.value)) + return + } +} + +class CmdMulIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjIntValue(a) + val right = frame.getLocalObjIntValue(b) + frame.storeObjResult(dst, ObjInt.of(left * right)) + return + } +} + +class CmdDivIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjInt + val right = frame.slotToObj(b) as ObjInt + frame.storeObjResult(dst, ObjInt.of(left.value / right.value)) + return + } +} + +class CmdDivIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjIntValue(a) + val right = frame.getLocalObjIntValue(b) + frame.storeObjResult(dst, ObjInt.of(left / right)) + return + } +} + +class CmdModIntObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjInt + val right = frame.slotToObj(b) as ObjInt + frame.storeObjResult(dst, ObjInt.of(left.value % right.value)) + return + } +} + +class CmdModIntObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjIntValue(a) + val right = frame.getLocalObjIntValue(b) + frame.storeObjResult(dst, ObjInt.of(left % right)) + return + } +} + +class CmdAddRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjReal + val right = frame.slotToObj(b) as ObjReal + frame.storeObjResult(dst, ObjReal.of(left.value + right.value)) + return + } +} + +class CmdAddRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjRealValue(a) + val right = frame.getLocalObjRealValue(b) + frame.storeObjResult(dst, ObjReal.of(left + right)) + return + } +} + +class CmdSubRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjReal + val right = frame.slotToObj(b) as ObjReal + frame.storeObjResult(dst, ObjReal.of(left.value - right.value)) + return + } +} + +class CmdSubRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjRealValue(a) + val right = frame.getLocalObjRealValue(b) + frame.storeObjResult(dst, ObjReal.of(left - right)) + return + } +} + +class CmdMulRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjReal + val right = frame.slotToObj(b) as ObjReal + frame.storeObjResult(dst, ObjReal.of(left.value * right.value)) + return + } +} + +class CmdMulRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjRealValue(a) + val right = frame.getLocalObjRealValue(b) + frame.storeObjResult(dst, ObjReal.of(left * right)) + return + } +} + +class CmdDivRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjReal + val right = frame.slotToObj(b) as ObjReal + frame.storeObjResult(dst, ObjReal.of(left.value / right.value)) + return + } +} + +class CmdDivRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjRealValue(a) + val right = frame.getLocalObjRealValue(b) + frame.storeObjResult(dst, ObjReal.of(left / right)) + return + } +} + +class CmdModRealObj(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val left = frame.slotToObj(a) as ObjReal + val right = frame.slotToObj(b) as ObjReal + frame.storeObjResult(dst, ObjReal.of(left.value % right.value)) + return + } +} + +class CmdModRealObjLocal(internal val a: Int, internal val b: Int, internal val dst: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + val left = frame.getLocalObjRealValue(a) + val right = frame.getLocalObjRealValue(b) + frame.storeObjResult(dst, ObjReal.of(left % right)) return } } @@ -1281,7 +2109,8 @@ class CmdAssignOpObj( } class CmdJmp(internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { frame.ip = target return } @@ -1296,6 +2125,16 @@ class CmdJmpIfTrue(internal val cond: Int, internal val target: Int) : Cmd() { } } +class CmdJmpIfTrueLocal(internal val cond: Int, internal val target: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + if (frame.getLocalBool(cond)) { + frame.ip = target + } + return + } +} + class CmdJmpIfFalse(internal val cond: Int, internal val target: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { if (!frame.getBool(cond)) { @@ -1305,6 +2144,16 @@ class CmdJmpIfFalse(internal val cond: Int, internal val target: Int) : Cmd() { } } +class CmdJmpIfFalseLocal(internal val cond: Int, internal val target: Int) : Cmd() { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { + if (!frame.getLocalBool(cond)) { + frame.ip = target + } + return + } +} + class CmdJmpIfEqInt(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { override suspend fun perform(frame: CmdFrame) { if (frame.getInt(a) == frame.getInt(b)) { @@ -1315,7 +2164,8 @@ class CmdJmpIfEqInt(internal val a: Int, internal val b: Int, internal val targe } class CmdJmpIfEqIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) == frame.getLocalInt(b)) { frame.ip = target } @@ -1333,7 +2183,8 @@ class CmdJmpIfNeqInt(internal val a: Int, internal val b: Int, internal val targ } class CmdJmpIfNeqIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) != frame.getLocalInt(b)) { frame.ip = target } @@ -1351,7 +2202,8 @@ class CmdJmpIfLtInt(internal val a: Int, internal val b: Int, internal val targe } class CmdJmpIfLtIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) < frame.getLocalInt(b)) { frame.ip = target } @@ -1369,7 +2221,8 @@ class CmdJmpIfLteInt(internal val a: Int, internal val b: Int, internal val targ } class CmdJmpIfLteIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) <= frame.getLocalInt(b)) { frame.ip = target } @@ -1387,7 +2240,8 @@ class CmdJmpIfGtInt(internal val a: Int, internal val b: Int, internal val targe } class CmdJmpIfGtIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) > frame.getLocalInt(b)) { frame.ip = target } @@ -1405,7 +2259,8 @@ class CmdJmpIfGteInt(internal val a: Int, internal val b: Int, internal val targ } class CmdJmpIfGteIntLocal(internal val a: Int, internal val b: Int, internal val target: Int) : Cmd() { - override suspend fun perform(frame: CmdFrame) { + override val isFast: Boolean = true + override fun performFast(frame: CmdFrame) { if (frame.getLocalInt(a) >= frame.getLocalInt(b)) { frame.ip = target } @@ -2858,6 +3713,28 @@ class CmdFrame( } internal fun getLocalSlotTypeCode(localIndex: Int): Byte = frame.getSlotTypeCode(localIndex) + internal fun isFastLocalSlot(slot: Int): Boolean { + if (slot < fn.scopeSlotCount) return false + val localIndex = slot - fn.scopeSlotCount + return fn.localSlotCaptures.getOrNull(localIndex) != true + } + + internal fun getLocalObjIntValue(localIndex: Int): Long { + return when (frame.getSlotTypeCode(localIndex)) { + SlotType.INT.code -> frame.getInt(localIndex) + SlotType.OBJ.code -> (frame.getObj(localIndex) as ObjInt).value + else -> error("expected ObjInt/INT in local slot $localIndex") + } + } + + internal fun getLocalObjRealValue(localIndex: Int): Double { + return when (frame.getSlotTypeCode(localIndex)) { + SlotType.REAL.code -> frame.getReal(localIndex) + SlotType.INT.code -> frame.getInt(localIndex).toDouble() + SlotType.OBJ.code -> (frame.getObj(localIndex) as ObjReal).value + else -> error("expected ObjReal/REAL in local slot $localIndex") + } + } internal fun applyCaptureRecords() { val captureRecords = scope.captureRecords ?: return @@ -3282,6 +4159,7 @@ class CmdFrame( } fun getLocalInt(local: Int): Long = frame.getInt(local) + fun getLocalReal(local: Int): Double = frame.getReal(local) fun setIntUnchecked(slot: Int, value: Long) { if (slot < fn.scopeSlotCount) { @@ -3337,6 +4215,10 @@ class CmdFrame( frame.setInt(local, value) } + fun setLocalReal(local: Int, value: Double) { + frame.setReal(local, value) + } + suspend fun getReal(slot: Int): Double { return if (slot < fn.scopeSlotCount) { getScopeSlotValue(slot).toDouble() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt index 2445abd..9a844cd 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt @@ -1,5 +1,5 @@ /* - * Copyright 2026 Sergey S. Chernov + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * */ package net.sergeych.lyng.bytecode @@ -98,6 +99,36 @@ enum class Opcode(val code: Int) { CMP_NEQ_OBJ(0x6D), CMP_REF_EQ_OBJ(0x6E), CMP_REF_NEQ_OBJ(0x6F), + CMP_EQ_STR(0xD6), + CMP_NEQ_STR(0xD7), + CMP_LT_STR(0xD8), + CMP_LTE_STR(0xD9), + CMP_GT_STR(0xDA), + CMP_GTE_STR(0xDB), + CMP_EQ_INT_OBJ(0xDC), + CMP_NEQ_INT_OBJ(0xDD), + CMP_LT_INT_OBJ(0xDE), + CMP_LTE_INT_OBJ(0xDF), + CMP_GT_INT_OBJ(0xE0), + CMP_GTE_INT_OBJ(0xE1), + CMP_EQ_REAL_OBJ(0xE2), + CMP_NEQ_REAL_OBJ(0xE3), + CMP_LT_REAL_OBJ(0xE4), + CMP_LTE_REAL_OBJ(0xE5), + CMP_GT_REAL_OBJ(0xE6), + CMP_GTE_REAL_OBJ(0xE7), + UNBOX_INT_OBJ(0xF2), + UNBOX_REAL_OBJ(0xF3), + ADD_INT_OBJ(0xE8), + SUB_INT_OBJ(0xE9), + MUL_INT_OBJ(0xEA), + DIV_INT_OBJ(0xEB), + MOD_INT_OBJ(0xEC), + ADD_REAL_OBJ(0xED), + SUB_REAL_OBJ(0xEE), + MUL_REAL_OBJ(0xEF), + DIV_REAL_OBJ(0xF0), + MOD_REAL_OBJ(0xF1), NOT_BOOL(0x70), AND_BOOL(0x71), diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt index 7c2ca29..644bfb5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,9 +73,11 @@ data class ObjBool(val value: Boolean) : Obj() { override suspend fun deserialize(scope: Scope, decoder: LynonDecoder,lynonType: LynonType?): Obj { return ObjBool(decoder.unpackBoolean()) } + }.apply { + isClosed = true } } } val ObjTrue = ObjBool(true) -val ObjFalse = ObjBool(false) \ No newline at end of file +val ObjFalse = ObjBool(false) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt index 409cab7..060e651 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjClass.kt @@ -109,6 +109,7 @@ open class ObjClass( var isAnonymous: Boolean = false var isAbstract: Boolean = false + var isClosed: Boolean = false // Stable identity and simple structural version for PICs val classId: Long = ClassIdGen.nextId() @@ -399,7 +400,16 @@ open class ObjClass( internal fun fieldSlotMap(): Map = ensureFieldSlots() internal fun fieldRecordForId(fieldId: Int): ObjRecord? { ensureFieldSlots() - return fieldSlotMap.values.firstOrNull { it.slot == fieldId }?.record + fieldSlotMap.values.firstOrNull { it.slot == fieldId }?.record?.let { return it } + // Fallback: resolve by id through name mapping if slot map is stale. + val name = fieldIdMap.entries.firstOrNull { it.value == fieldId }?.key + if (name != null) { + for (cls in mro) { + cls.members[name]?.let { return it } + cls.classScope?.objects?.get(name)?.let { return it } + } + } + return null } internal fun resolveInstanceMember(name: String): ResolvedMember? = ensureInstanceMemberCache()[name] internal fun methodSlotCount(): Int { @@ -423,9 +433,18 @@ open class ObjClass( if (rec.methodId == methodId) return rec } } + // Final fallback: resolve by id through name mapping if slot map is stale. + val name = methodIdMap.entries.firstOrNull { it.value == methodId }?.key + if (name != null) { + for (cls in mro) { + cls.members[name]?.let { return it } + cls.classScope?.objects?.get(name)?.let { return it } + } + } return null } + internal fun instanceFieldIdMap(): Map { val result = mutableMapOf() for (cls in mro) { @@ -479,7 +498,13 @@ open class ObjClass( fieldIdMap[name] = existingId return existingId } - val id = fieldIdMap.getOrPut(name) { nextFieldId++ } + val id = fieldIdMap[name] ?: run { + val next = nextFieldId++ + fieldIdMap[name] = next + // Field id map affects slot layout; invalidate caches when a new id is assigned. + layoutVersion += 1 + next + } return id } @@ -493,7 +518,13 @@ open class ObjClass( } return existingId } - val id = methodIdMap.getOrPut(name) { nextMethodId++ } + val id = methodIdMap[name] ?: run { + val next = nextMethodId++ + methodIdMap[name] = next + // Method id map affects slot layout; invalidate caches when a new id is assigned. + layoutVersion += 1 + next + } if (id >= nextMethodId) { nextMethodId = id + 1 } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt index ae21cac..8a72ee3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -189,6 +189,7 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu else -> scope.raiseIllegalState("illegal type code for Int: $lynonType") } }.apply { + isClosed = true addFnDoc( name = "toInt", doc = "Returns this integer (identity operation).", diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt index 1aff927..13685b2 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package net.sergeych.lyng.obj import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive -import net.sergeych.lyng.Pos import net.sergeych.lyng.Scope import net.sergeych.lyng.miniast.addConstDoc import net.sergeych.lyng.miniast.addFnDoc @@ -122,6 +121,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric { override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj = of(decoder.unpackDouble()) }.apply { + isClosed = true // roundToInt: number rounded to the nearest integer addConstDoc( name = "roundToInt", diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt index 14648c5..2cc0bae 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjString.kt @@ -25,8 +25,8 @@ import net.sergeych.lyng.PerfFlags import net.sergeych.lyng.Pos import net.sergeych.lyng.RegexCache import net.sergeych.lyng.Scope -import net.sergeych.lyng.requireScope import net.sergeych.lyng.miniast.* +import net.sergeych.lyng.requireScope import net.sergeych.lynon.LynonDecoder import net.sergeych.lynon.LynonEncoder import net.sergeych.lynon.LynonType @@ -137,6 +137,7 @@ data class ObjString(val value: String) : Obj() { override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj = ObjString(decoder.unpackBinaryData().decodeToString()) }.apply { + isClosed = true addFnDoc( name = "iterator", doc = "Iterator over characters of this string.", diff --git a/lynglib/src/commonTest/kotlin/RepresentativeBenchmarkTest.kt b/lynglib/src/commonTest/kotlin/RepresentativeBenchmarkTest.kt new file mode 100644 index 0000000..040e29c --- /dev/null +++ b/lynglib/src/commonTest/kotlin/RepresentativeBenchmarkTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import kotlinx.coroutines.test.runTest +import net.sergeych.lyng.Benchmarks +import net.sergeych.lyng.Script +import net.sergeych.lyng.obj.ObjInt +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.TimeSource + +class RepresentativeBenchmarkTest { + @Test + fun benchmarkMixedOps() = runTest { + if (!Benchmarks.enabled) return@runTest + val iterations = 40000 + val script = """ + fun mixedBench(n) { + var acc = 0 + var len = 0 + val list = [1,2,3,4,5,6,7,8] + val map = {"a":1, "b":2, "c":3} + fun bump(x) { x + 1 } + var i = 0 + while(i < n) { + acc += i + acc += bump(i) + if( i % 2 == 0 ) acc += 3 else acc -= 1 + acc += list[i % 8] + acc += map["a"] + if( i % 7 == 0 ) len += 1 + if( i % 11 == 0 ) len += 1 + i++ + } + acc + len + } + """.trimIndent() + + val scope = Script.newScope() + scope.eval(script) + val expected = expectedValue(iterations) + + val start = TimeSource.Monotonic.markNow() + val result = scope.eval("mixedBench($iterations)") as ObjInt + val elapsedMs = start.elapsedNow().inWholeMilliseconds + println("[DEBUG_LOG] [BENCH] mixed-ops elapsed=${elapsedMs} ms") + assertEquals(expected, result.value) + } + + private fun expectedValue(iterations: Int): Long { + val list = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8) + var acc = 0L + var len = 0L + for (i in 0 until iterations) { + acc += i + acc += i + 1L + if (i % 2 == 0) acc += 3 else acc -= 1 + acc += list[i % list.size] + acc += 1 + if (i % 7 == 0) len += 1 + if (i % 11 == 0) len += 1 + } + return acc + len + } +} diff --git a/lynglib/src/commonTest/kotlin/RepresentativeObjectBenchmarkTest.kt b/lynglib/src/commonTest/kotlin/RepresentativeObjectBenchmarkTest.kt new file mode 100644 index 0000000..9ea45ae --- /dev/null +++ b/lynglib/src/commonTest/kotlin/RepresentativeObjectBenchmarkTest.kt @@ -0,0 +1,163 @@ +/* + * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import kotlinx.coroutines.test.runTest +import net.sergeych.lyng.Benchmarks +import net.sergeych.lyng.BytecodeBodyProvider +import net.sergeych.lyng.Script +import net.sergeych.lyng.Statement +import net.sergeych.lyng.bytecode.* +import net.sergeych.lyng.obj.ObjInt +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.TimeSource + +class RepresentativeObjectBenchmarkTest { + @Test + fun benchmarkObjectOps() = runTest { + if (!Benchmarks.enabled) return@runTest + val iterations = 20000 + val script = """ + fun objectBench(n) { + var acc = 0 + var s = "" + val list = ["a","b","c","d","e","f","g","h","i","j"] + val rlist = [1.0,2.0,3.0,4.0,5.0] + val map = {"a":1, "b":2, "c":3, "d":4} + var i = 0 + while(i < n) { + val k = list[i % 10] + val v = map[k] ?: 0 + val j = i % 10 + val r = i * 0.5 + val rr = rlist[j % 5] + val oi: Object = i + val oj: Object = j + val or: Object = r + val or2: Object = r + 1.0 + s = s + k + if( k in list ) acc += 1 + if( k == "a" ) acc += v else acc -= 1 + if( k != "z" ) acc += 1 + if( k < "m" ) acc += 1 else acc -= 1 + if( k >= "d" ) acc += 1 else acc -= 1 + if( j < 7 ) acc += 1 else acc -= 1 + if( j >= 3 ) acc += 1 else acc -= 1 + if( r <= 2.5 ) acc += 1 else acc -= 1 + if( r > 3.5 ) acc += 1 else acc -= 1 + if( rr < 3.5 ) acc += 1 else acc -= 1 + if( rr >= 2.5 ) acc += 1 else acc -= 1 + if( oi == oj ) acc += 1 else acc -= 1 + if( oi < oj ) acc += 1 else acc -= 1 + if( or > or2 ) acc += 1 else acc -= 1 + if( or <= or2 ) acc += 1 else acc -= 1 + if( i % 4 == 0 ) acc += list.size + i++ + } + acc + s.size + } + """.trimIndent() + + val scope = Script.newScope() + scope.eval(script) + val expected = expectedValue(iterations) + dumpFunctionBytecode(scope, "objectBench") + dumpFastCompareStats(scope, "objectBench") + + val start = TimeSource.Monotonic.markNow() + val result = scope.eval("objectBench($iterations)") as ObjInt + val elapsedMs = start.elapsedNow().inWholeMilliseconds + println("[DEBUG_LOG] [BENCH] object-ops elapsed=${elapsedMs} ms") + assertEquals(expected, result.value) + } + + private fun expectedValue(iterations: Int): Long { + val list = arrayOf("a","b","c","d","e","f","g","h","i","j") + val rlist = doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0) + val map = mapOf("a" to 1, "b" to 2, "c" to 3, "d" to 4) + var acc = 0L + var s = "" + for (i in 0 until iterations) { + val k = list[i % list.size] + val v = map[k] ?: 0 + val j = i % 10 + val r = i * 0.5 + val rr = rlist[j % 5] + val oi = i + val oj = j + val or = r + val or2 = r + 1.0 + s += k + acc += 1 + if (k == "a") acc += v else acc -= 1 + if (k != "z") acc += 1 + if (k < "m") acc += 1 else acc -= 1 + if (k >= "d") acc += 1 else acc -= 1 + if (j < 7) acc += 1 else acc -= 1 + if (j >= 3) acc += 1 else acc -= 1 + if (r <= 2.5) acc += 1 else acc -= 1 + if (r > 3.5) acc += 1 else acc -= 1 + if (rr < 3.5) acc += 1 else acc -= 1 + if (rr >= 2.5) acc += 1 else acc -= 1 + if (oi == oj) acc += 1 else acc -= 1 + if (oi < oj) acc += 1 else acc -= 1 + if (or > or2) acc += 1 else acc -= 1 + if (or <= or2) acc += 1 else acc -= 1 + if (i % 4 == 0) acc += list.size + } + return acc + s.length + } + + private fun dumpFunctionBytecode(scope: net.sergeych.lyng.Scope, name: String) { + val disasm = scope.disassembleSymbol(name) + println("[DEBUG_LOG] [BENCH] object-ops cmd:\n$disasm") + } + + private fun dumpFastCompareStats(scope: net.sergeych.lyng.Scope, name: String) { + val fn = resolveBytecodeFunction(scope, name) ?: return + var strLocal = 0 + var intObjLocal = 0 + var realObjLocal = 0 + for (cmd in fn.cmds) { + when (cmd) { + is CmdCmpEqStrLocal, + is CmdCmpNeqStrLocal, + is CmdCmpLtStrLocal, + is CmdCmpGteStrLocal -> strLocal += 1 + is CmdCmpEqIntObjLocal, + is CmdCmpNeqIntObjLocal, + is CmdCmpLtIntObjLocal, + is CmdCmpGteIntObjLocal -> intObjLocal += 1 + is CmdCmpEqRealObjLocal, + is CmdCmpNeqRealObjLocal, + is CmdCmpLtRealObjLocal, + is CmdCmpGteRealObjLocal -> realObjLocal += 1 + else -> {} + } + } + println( + "[DEBUG_LOG] [BENCH] object-ops fast-compare local cmds: str=$strLocal intObj=$intObjLocal realObj=$realObjLocal" + ) + } + + private fun resolveBytecodeFunction(scope: net.sergeych.lyng.Scope, name: String): CmdFunction? { + val record = scope.get(name) ?: return null + val stmt = record.value as? Statement ?: return null + return (stmt as? BytecodeStatement)?.bytecodeFunction() + ?: (stmt as? BytecodeBodyProvider)?.bytecodeBody()?.bytecodeFunction() + } +} diff --git a/lynglib/src/commonTest/kotlin/TypesTest.kt b/lynglib/src/commonTest/kotlin/TypesTest.kt index c591896..aef0618 100644 --- a/lynglib/src/commonTest/kotlin/TypesTest.kt +++ b/lynglib/src/commonTest/kotlin/TypesTest.kt @@ -187,12 +187,24 @@ class TypesTest { val base = [1, 2] acceptInts([...base, 3]) """.trimIndent()) + eval(""" + fun acceptReals(xs: List) { } + acceptReals([1.0, 2.0, 3.0]) + val base = [1.0, 2.0] + acceptReals([...base, 3.0]) + """.trimIndent()) assertFailsWith { eval(""" fun acceptInts(xs: List) { } acceptInts([1, "a"]) """.trimIndent()) } + assertFailsWith { + eval(""" + fun acceptReals(xs: List) { } + acceptReals([1.0, "a"]) + """.trimIndent()) + } } @Test diff --git a/notes/nested_loop_vm_state.md b/notes/nested_loop_vm_state.md index 13e9d4e..5f3eef8 100644 --- a/notes/nested_loop_vm_state.md +++ b/notes/nested_loop_vm_state.md @@ -37,6 +37,12 @@ - 2026-02-15 baseline (fused int-compare jumps): 74 ms. - Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'` - Notes: loop range checks use `JMP_IF_GTE_INT` (no CMP+bool temp). +- 2026-02-15 experiment (fast non-suspend cmds in hot path): 57 ms. + - Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'` + - Notes: fast path for local int ops + local JMP_IF_FALSE/TRUE in VM. +- 2026-02-15 experiment (full fast-path sweep + capture-safe locals): 59 ms. + - Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'` + - Notes: local numeric/bool/mixed-compare fast ops gated by non-captured locals. ### Hypothesis for Native slowdown - Suspend/virtual dispatch per opcode dominates on K/N, even with no allocations in int ops. diff --git a/notes/vm_fastpath_plan.md b/notes/vm_fastpath_plan.md new file mode 100644 index 0000000..12ae4a3 --- /dev/null +++ b/notes/vm_fastpath_plan.md @@ -0,0 +1,49 @@ +# VM Fast-Path Plan (Non-Suspending Ops) + +## Goal +Reduce suspend overhead by routing safe, local-only ops through non-suspending fast paths while preserving semantics for captured locals and dynamic objects. + +## Completed +- [x] Local numeric/bool/conversion ops: add fast local variants and guard by non-captured locals. +- [x] Local jumps: `JMP_IF_TRUE/FALSE` and fused int jumps fast path. +- [x] **Object arithmetic ops** (`ADD_OBJ/SUB_OBJ/MUL_OBJ/DIV_OBJ/MOD_OBJ`): add fast-path for local numeric slots with fallback to slow path when non-numeric or captured. +- [x] Full `:lynglib:jvmTest` green after changes. + +## In Progress / Next +- [ ] Object comparisons (`CMP_*_OBJ`) fast-path on local numeric slots (guarded, fallback to slow path). +- [ ] Local `MOVE_OBJ` safe fast-path (only if slot is not `FrameSlotRef`/`RecordSlotRef`, or add explicit unwrapping). +- [ ] Address ops (`LOAD_*_ADDR` / `STORE_*_ADDR`) non-suspend variants when addr already resolved. +- [ ] Confirm wasm/js behavior unchanged (if needed). + +## Guardrails +- Never treat captured locals as fast locals; route them through slow path. +- Fast path must only execute when slot types are primitive numeric/bool and stored directly in frame. +- If fast-path preconditions fail, fall back to suspend `perform()`. + +## Test Gate +- `./gradlew :lynglib:jvmTest` +- Benchmarks optional: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'` + +## A/B Benchmark (Representative) +- Baseline (fast-path stashed): 194 ms +- With fast-path changes: 186 ms +- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*RepresentativeBenchmarkTest*'` + +## A/B Benchmark (Representative Object Ops) +- Baseline (fast-path stashed): 106 ms +- With fast-path changes: 108 ms +- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*RepresentativeObjectBenchmarkTest*'` + +## A/B Benchmark (Representative Object Ops, extended comparisons) +- Baseline (ObjString only): 141 ms +- With ObjString + ObjInt/ObjReal compare ops: 137 ms +- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*RepresentativeObjectBenchmarkTest*'` + +## A/B Benchmark (Representative Object Ops, object numeric compares) +- Baseline (no Obj* compare ops): 153 ms +- With ObjString + ObjInt/ObjReal compare ops: 149 ms +- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*RepresentativeObjectBenchmarkTest*'` + +## A/B Benchmark (Trust type decls for Obj* compares) +- With ObjString + ObjInt/ObjReal compare ops + type-decl trust: 157 ms +- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*RepresentativeObjectBenchmarkTest*'`