VM optimizations

This commit is contained in:
Sergey Chernov 2026-02-16 06:16:29 +03:00
parent 637258581d
commit fd2da1efd3
18 changed files with 2847 additions and 331 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*
*/ */
package net.sergeych.lyng package net.sergeych.lyng
import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.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
data class ClassDeclBaseSpec( data class ClassDeclBaseSpec(
val name: String, val name: String,
@ -51,11 +46,16 @@ internal suspend fun executeClassDecl(
bodyCaptureRecords: List<ObjRecord>? = null, bodyCaptureRecords: List<ObjRecord>? = null,
bodyCaptureNames: List<String>? = null bodyCaptureNames: List<String>? = null
): Obj { ): Obj {
fun checkClosedParents(parents: List<ObjClass>, pos: Pos) {
val closedParent = parents.firstOrNull { it.isClosed } ?: return
throw ScriptError(pos, "can't inherit from closed class ${closedParent.className}")
}
if (spec.isObject) { if (spec.isObject) {
val parentClasses = spec.baseSpecs.map { baseSpec -> val parentClasses = spec.baseSpecs.map { baseSpec ->
val rec = scope[baseSpec.name] ?: throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}") 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") (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()) val newClass = ObjInstanceClass(spec.className, *parentClasses.toTypedArray())
newClass.isAnonymous = spec.isAnonymous newClass.isAnonymous = spec.isAnonymous
@ -106,6 +106,7 @@ internal suspend fun executeClassDecl(
if (rec == null) throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}") if (rec == null) throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}")
throw ScriptError(spec.startPos, "${baseSpec.name} is not a class") throw ScriptError(spec.startPos, "${baseSpec.name} is not a class")
} }
checkClosedParents(parentClasses, spec.startPos)
val constructorCode = object : Statement() { val constructorCode = object : Statement() {
override val pos: Pos = spec.startPos override val pos: Pos = spec.startPos

View File

@ -18,11 +18,7 @@
package net.sergeych.lyng package net.sergeych.lyng
import net.sergeych.lyng.Compiler.Companion.compile import net.sergeych.lyng.Compiler.Companion.compile
import net.sergeych.lyng.bytecode.BytecodeStatement import net.sergeych.lyng.bytecode.*
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.miniast.* import net.sergeych.lyng.miniast.*
import net.sergeych.lyng.obj.* import net.sergeych.lyng.obj.*
import net.sergeych.lyng.pacman.ImportManager import net.sergeych.lyng.pacman.ImportManager
@ -1643,6 +1639,7 @@ class Compiler(
forcedLocalSlotInfo = forcedLocalInfo, forcedLocalSlotInfo = forcedLocalInfo,
forcedLocalScopeId = forcedLocalScopeId, forcedLocalScopeId = forcedLocalScopeId,
slotTypeByScopeId = slotTypeByScopeId, slotTypeByScopeId = slotTypeByScopeId,
slotTypeDeclByScopeId = slotTypeDeclByScopeId,
knownNameObjClass = knownClassMapForBytecode(), knownNameObjClass = knownClassMapForBytecode(),
knownObjectNames = objectDeclNames, knownObjectNames = objectDeclNames,
classFieldTypesByName = classFieldTypesByName, classFieldTypesByName = classFieldTypesByName,
@ -1941,6 +1938,7 @@ class Compiler(
scopeSlotNameSet = scopeSlotNameSet, scopeSlotNameSet = scopeSlotNameSet,
moduleScopeId = moduleScopeId, moduleScopeId = moduleScopeId,
slotTypeByScopeId = slotTypeByScopeId, slotTypeByScopeId = slotTypeByScopeId,
slotTypeDeclByScopeId = slotTypeDeclByScopeId,
knownNameObjClass = knownClassMapForBytecode(), knownNameObjClass = knownClassMapForBytecode(),
knownObjectNames = objectDeclNames, knownObjectNames = objectDeclNames,
classFieldTypesByName = classFieldTypesByName, classFieldTypesByName = classFieldTypesByName,
@ -1969,6 +1967,7 @@ class Compiler(
scopeSlotNameSet = scopeSlotNameSet, scopeSlotNameSet = scopeSlotNameSet,
moduleScopeId = moduleScopeId, moduleScopeId = moduleScopeId,
slotTypeByScopeId = slotTypeByScopeId, slotTypeByScopeId = slotTypeByScopeId,
slotTypeDeclByScopeId = slotTypeDeclByScopeId,
knownNameObjClass = knownClassMapForBytecode(), knownNameObjClass = knownClassMapForBytecode(),
knownObjectNames = objectDeclNames, knownObjectNames = objectDeclNames,
classFieldTypesByName = classFieldTypesByName, classFieldTypesByName = classFieldTypesByName,
@ -2022,6 +2021,7 @@ class Compiler(
globalSlotInfo = globalSlotInfo, globalSlotInfo = globalSlotInfo,
globalSlotScopeId = globalSlotScopeId, globalSlotScopeId = globalSlotScopeId,
slotTypeByScopeId = slotTypeByScopeId, slotTypeByScopeId = slotTypeByScopeId,
slotTypeDeclByScopeId = slotTypeDeclByScopeId,
knownNameObjClass = knownNames, knownNameObjClass = knownNames,
knownObjectNames = objectDeclNames, knownObjectNames = objectDeclNames,
classFieldTypesByName = classFieldTypesByName, classFieldTypesByName = classFieldTypesByName,
@ -7580,6 +7580,10 @@ class Compiler(
val info = compileClassInfos[name] ?: return null val info = compileClassInfos[name] ?: return null
val stub = compileClassStubs.getOrPut(info.name) { val stub = compileClassStubs.getOrPut(info.name) {
val parents = info.baseNames.mapNotNull { resolveClassByName(it) } 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()) ObjInstanceClass(info.name, *parents.toTypedArray())
} }
if (stub is ObjInstanceClass) { if (stub is ObjInstanceClass) {

View File

@ -59,6 +59,7 @@ class BytecodeStatement private constructor(
callableReturnTypeByName: Map<String, ObjClass> = emptyMap(), callableReturnTypeByName: Map<String, ObjClass> = emptyMap(),
externCallableNames: Set<String> = emptySet(), externCallableNames: Set<String> = emptySet(),
lambdaCaptureEntriesByRef: Map<ValueFnRef, List<LambdaCaptureEntry>> = emptyMap(), lambdaCaptureEntriesByRef: Map<ValueFnRef, List<LambdaCaptureEntry>> = emptyMap(),
slotTypeDeclByScopeId: Map<Int, Map<Int, TypeDecl>> = emptyMap(),
): Statement { ): Statement {
if (statement is BytecodeStatement) return statement if (statement is BytecodeStatement) return statement
val hasUnsupported = containsUnsupportedStatement(statement) val hasUnsupported = containsUnsupportedStatement(statement)
@ -83,6 +84,7 @@ class BytecodeStatement private constructor(
globalSlotInfo = globalSlotInfo, globalSlotInfo = globalSlotInfo,
globalSlotScopeId = globalSlotScopeId, globalSlotScopeId = globalSlotScopeId,
slotTypeByScopeId = slotTypeByScopeId, slotTypeByScopeId = slotTypeByScopeId,
slotTypeDeclByScopeId = slotTypeDeclByScopeId,
knownNameObjClass = knownNameObjClass, knownNameObjClass = knownNameObjClass,
knownObjectNames = knownObjectNames, knownObjectNames = knownObjectNames,
classFieldTypesByName = classFieldTypesByName, classFieldTypesByName = classFieldTypesByName,

View File

@ -102,7 +102,7 @@ class CmdBuilder {
} }
operands[i] = v operands[i] = v
} }
cmds.add(createCmd(ins.op, operands, scopeSlotCount)) cmds.add(createCmd(ins.op, operands, scopeSlotCount, localSlotCaptures))
} }
return CmdFunction( return CmdFunction(
name = name, name = name,
@ -128,6 +128,7 @@ class CmdBuilder {
Opcode.NOP, Opcode.RET_VOID, Opcode.POP_SCOPE, Opcode.POP_SLOT_PLAN, Opcode.POP_TRY, Opcode.NOP, Opcode.RET_VOID, Opcode.POP_SCOPE, Opcode.POP_SLOT_PLAN, Opcode.POP_TRY,
Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING -> emptyList() Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING -> emptyList()
Opcode.MOVE_OBJ, Opcode.MOVE_INT, Opcode.MOVE_REAL, Opcode.MOVE_BOOL, Opcode.BOX_OBJ, 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.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
Opcode.OBJ_TO_BOOL, Opcode.GET_OBJ_CLASS, Opcode.OBJ_TO_BOOL, Opcode.GET_OBJ_CLASS,
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT, 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_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_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_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.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.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ,
Opcode.AND_BOOL, Opcode.OR_BOOL -> Opcode.AND_BOOL, Opcode.OR_BOOL ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
@ -241,19 +249,37 @@ class CmdBuilder {
ID, 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) { return when (op) {
Opcode.NOP -> CmdNop() Opcode.NOP -> CmdNop()
Opcode.MOVE_OBJ -> CmdMoveObj(operands[0], operands[1]) 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) CmdMoveIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount)
} else { } else {
CmdMoveInt(operands[0], operands[1]) CmdMoveInt(operands[0], operands[1])
} }
Opcode.MOVE_REAL -> CmdMoveReal(operands[0], operands[1]) Opcode.MOVE_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) {
Opcode.MOVE_BOOL -> CmdMoveBool(operands[0], 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_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) CmdConstIntLocal(operands[0], operands[1] - scopeSlotCount)
} else { } else {
CmdConstInt(operands[0], operands[1]) CmdConstInt(operands[0], operands[1])
@ -263,6 +289,16 @@ class CmdBuilder {
Opcode.CONST_NULL -> CmdConstNull(operands[0]) Opcode.CONST_NULL -> CmdConstNull(operands[0])
Opcode.MAKE_LAMBDA_FN -> CmdMakeLambda(operands[0], operands[1]) Opcode.MAKE_LAMBDA_FN -> CmdMakeLambda(operands[0], operands[1])
Opcode.BOX_OBJ -> CmdBoxObj(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.OBJ_TO_BOOL -> CmdObjToBool(operands[0], operands[1])
Opcode.GET_OBJ_CLASS -> CmdGetObjClass(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]) 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.STORE_REAL_ADDR -> CmdStoreRealAddr(operands[0], operands[1])
Opcode.LOAD_BOOL_ADDR -> CmdLoadBoolAddr(operands[0], operands[1]) Opcode.LOAD_BOOL_ADDR -> CmdLoadBoolAddr(operands[0], operands[1])
Opcode.STORE_BOOL_ADDR -> CmdStoreBoolAddr(operands[0], operands[1]) Opcode.STORE_BOOL_ADDR -> CmdStoreBoolAddr(operands[0], operands[1])
Opcode.INT_TO_REAL -> CmdIntToReal(operands[0], operands[1]) Opcode.INT_TO_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) {
Opcode.REAL_TO_INT -> CmdRealToInt(operands[0], operands[1]) CmdIntToRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount)
Opcode.BOOL_TO_INT -> CmdBoolToInt(operands[0], operands[1]) } else {
Opcode.INT_TO_BOOL -> CmdIntToBool(operands[0], operands[1]) CmdIntToReal(operands[0], operands[1])
Opcode.ADD_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount && operands[2] >= scopeSlotCount) { }
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) CmdAddIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdAddInt(operands[0], operands[1], operands[2]) 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) CmdSubIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdSubInt(operands[0], operands[1], operands[2]) 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) CmdMulIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdMulInt(operands[0], operands[1], operands[2]) 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) CmdDivIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdDivInt(operands[0], operands[1], operands[2]) 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) CmdModIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdModInt(operands[0], operands[1], operands[2]) CmdModInt(operands[0], operands[1], operands[2])
} }
Opcode.NEG_INT -> CmdNegInt(operands[0], operands[1]) Opcode.NEG_INT -> if (isFastLocal(operands[0]) && isFastLocal(operands[1])) {
Opcode.INC_INT -> if (operands[0] >= scopeSlotCount) { CmdNegIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount)
} else {
CmdNegInt(operands[0], operands[1])
}
Opcode.INC_INT -> if (isFastLocal(operands[0])) {
CmdIncIntLocal(operands[0] - scopeSlotCount) CmdIncIntLocal(operands[0] - scopeSlotCount)
} else { } else {
CmdIncInt(operands[0]) CmdIncInt(operands[0])
} }
Opcode.DEC_INT -> if (operands[0] >= scopeSlotCount) { Opcode.DEC_INT -> if (isFastLocal(operands[0])) {
CmdDecIntLocal(operands[0] - scopeSlotCount) CmdDecIntLocal(operands[0] - scopeSlotCount)
} else { } else {
CmdDecInt(operands[0]) CmdDecInt(operands[0])
} }
Opcode.ADD_REAL -> CmdAddReal(operands[0], operands[1], operands[2]) Opcode.ADD_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.SUB_REAL -> CmdSubReal(operands[0], operands[1], operands[2]) CmdAddRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.MUL_REAL -> CmdMulReal(operands[0], operands[1], operands[2]) } else {
Opcode.DIV_REAL -> CmdDivReal(operands[0], operands[1], operands[2]) CmdAddReal(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.SUB_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.OR_INT -> CmdOrInt(operands[0], operands[1], operands[2]) CmdSubRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.XOR_INT -> CmdXorInt(operands[0], operands[1], operands[2]) } else {
Opcode.SHL_INT -> CmdShlInt(operands[0], operands[1], operands[2]) CmdSubReal(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.MUL_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.INV_INT -> CmdInvInt(operands[0], operands[1]) CmdMulRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.CMP_EQ_INT -> if (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) CmdCmpEqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpEqInt(operands[0], operands[1], operands[2]) 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) CmdCmpNeqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpNeqInt(operands[0], operands[1], operands[2]) 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) CmdCmpLtIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpLtInt(operands[0], operands[1], operands[2]) 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) CmdCmpLteIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpLteInt(operands[0], operands[1], operands[2]) 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) CmdCmpGtIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpGtInt(operands[0], operands[1], operands[2]) 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) CmdCmpGteIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
} else { } else {
CmdCmpGteInt(operands[0], operands[1], operands[2]) CmdCmpGteInt(operands[0], operands[1], operands[2])
} }
Opcode.CMP_EQ_REAL -> CmdCmpEqReal(operands[0], operands[1], operands[2]) Opcode.CMP_EQ_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.CMP_NEQ_REAL -> CmdCmpNeqReal(operands[0], operands[1], operands[2]) CmdCmpEqRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.CMP_LT_REAL -> CmdCmpLtReal(operands[0], operands[1], operands[2]) } else {
Opcode.CMP_LTE_REAL -> CmdCmpLteReal(operands[0], operands[1], operands[2]) CmdCmpEqReal(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_NEQ_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.CMP_EQ_BOOL -> CmdCmpEqBool(operands[0], operands[1], operands[2]) CmdCmpNeqRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.CMP_NEQ_BOOL -> CmdCmpNeqBool(operands[0], operands[1], operands[2]) } else {
Opcode.CMP_EQ_INT_REAL -> CmdCmpEqIntReal(operands[0], operands[1], operands[2]) CmdCmpNeqReal(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 -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.CMP_LT_REAL_INT -> CmdCmpLtRealInt(operands[0], operands[1], operands[2]) CmdCmpLtRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.CMP_LTE_INT_REAL -> CmdCmpLteIntReal(operands[0], operands[1], operands[2]) } else {
Opcode.CMP_LTE_REAL_INT -> CmdCmpLteRealInt(operands[0], operands[1], operands[2]) CmdCmpLtReal(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_LTE_REAL -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.CMP_GTE_INT_REAL -> CmdCmpGteIntReal(operands[0], operands[1], operands[2]) CmdCmpLteRealLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.CMP_GTE_REAL_INT -> CmdCmpGteRealInt(operands[0], operands[1], operands[2]) } else {
Opcode.CMP_NEQ_INT_REAL -> CmdCmpNeqIntReal(operands[0], operands[1], operands[2]) CmdCmpLteReal(operands[0], operands[1], operands[2])
Opcode.CMP_NEQ_REAL_INT -> CmdCmpNeqRealInt(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_EQ_OBJ -> CmdCmpEqObj(operands[0], operands[1], operands[2])
Opcode.CMP_NEQ_OBJ -> CmdCmpNeqObj(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_EQ_OBJ -> CmdCmpRefEqObj(operands[0], operands[1], operands[2])
Opcode.CMP_REF_NEQ_OBJ -> CmdCmpRefNeqObj(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.CMP_EQ_STR -> if (isFastLocal(operands[0]) && isFastLocal(operands[1]) && isFastLocal(operands[2])) {
Opcode.AND_BOOL -> CmdAndBool(operands[0], operands[1], operands[2]) CmdCmpEqStrLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2] - scopeSlotCount)
Opcode.OR_BOOL -> CmdOrBool(operands[0], operands[1], operands[2]) } 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_LT_OBJ -> CmdCmpLtObj(operands[0], operands[1], operands[2])
Opcode.CMP_LTE_OBJ -> CmdCmpLteObj(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_GT_OBJ -> CmdCmpGtObj(operands[0], operands[1], operands[2])
Opcode.CMP_GTE_OBJ -> CmdCmpGteObj(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.ADD_OBJ -> CmdAddObj(operands[0], operands[1], operands[2])
Opcode.SUB_OBJ -> CmdSubObj(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]) 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.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.ASSIGN_OP_OBJ -> CmdAssignOpObj(operands[0], operands[1], operands[2], operands[3], operands[4])
Opcode.JMP -> CmdJmp(operands[0]) Opcode.JMP -> CmdJmp(operands[0])
Opcode.JMP_IF_TRUE -> CmdJmpIfTrue(operands[0], operands[1]) Opcode.JMP_IF_TRUE -> if (operands[0] >= scopeSlotCount) {
Opcode.JMP_IF_FALSE -> CmdJmpIfFalse(operands[0], operands[1]) 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) { Opcode.JMP_IF_EQ_INT -> if (operands[0] >= scopeSlotCount && operands[1] >= scopeSlotCount) {
CmdJmpIfEqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2]) CmdJmpIfEqIntLocal(operands[0] - scopeSlotCount, operands[1] - scopeSlotCount, operands[2])
} else { } else {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*
*/ */
package net.sergeych.lyng.bytecode package net.sergeych.lyng.bytecode
@ -76,6 +77,8 @@ object CmdDisassembler {
is CmdMoveObj -> Opcode.MOVE_OBJ to intArrayOf(cmd.src, cmd.dst) is CmdMoveObj -> Opcode.MOVE_OBJ to intArrayOf(cmd.src, cmd.dst)
is CmdMoveInt -> Opcode.MOVE_INT 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 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 CmdMoveReal -> Opcode.MOVE_REAL to intArrayOf(cmd.src, cmd.dst)
is CmdMoveBool -> Opcode.MOVE_BOOL 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) 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 CmdLoadBoolAddr -> Opcode.LOAD_BOOL_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
is CmdStoreBoolAddr -> Opcode.STORE_BOOL_ADDR to intArrayOf(cmd.src, cmd.addrSlot) 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 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 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 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 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 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 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) 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 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 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 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 CmdIncInt -> Opcode.INC_INT to intArrayOf(cmd.slot)
is CmdIncIntLocal -> Opcode.INC_INT to intArrayOf(cmd.slot + fn.scopeSlotCount) is CmdIncIntLocal -> Opcode.INC_INT to intArrayOf(cmd.slot + fn.scopeSlotCount)
is CmdDecInt -> Opcode.DEC_INT to intArrayOf(cmd.slot) is CmdDecInt -> Opcode.DEC_INT to intArrayOf(cmd.slot)
is CmdDecIntLocal -> Opcode.DEC_INT to intArrayOf(cmd.slot + fn.scopeSlotCount) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 CmdJmpIfEqInt -> Opcode.JMP_IF_EQ_INT to intArrayOf(cmd.a, cmd.b, cmd.target)
is CmdJmpIfEqIntLocal -> Opcode.JMP_IF_EQ_INT to intArrayOf( is CmdJmpIfEqIntLocal -> Opcode.JMP_IF_EQ_INT to intArrayOf(
cmd.a + fn.scopeSlotCount, 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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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 CmdJmp -> Opcode.JMP to intArrayOf(cmd.target)
is CmdJmpIfTrue -> Opcode.JMP_IF_TRUE to intArrayOf(cmd.cond, 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 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 CmdRet -> Opcode.RET to intArrayOf(cmd.slot)
is CmdRetLabel -> Opcode.RET_LABEL to intArrayOf(cmd.labelId, cmd.slot) is CmdRetLabel -> Opcode.RET_LABEL to intArrayOf(cmd.labelId, cmd.slot)
is CmdRetVoid -> Opcode.RET_VOID to intArrayOf() is CmdRetVoid -> Opcode.RET_VOID to intArrayOf()
@ -298,6 +521,7 @@ object CmdDisassembler {
Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING, Opcode.CLEAR_PENDING_THROWABLE, Opcode.RETHROW_PENDING,
Opcode.ITER_POP, Opcode.ITER_CANCEL -> emptyList() Opcode.ITER_POP, Opcode.ITER_CANCEL -> emptyList()
Opcode.MOVE_OBJ, Opcode.MOVE_INT, Opcode.MOVE_REAL, Opcode.MOVE_BOOL, Opcode.BOX_OBJ, 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.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT -> Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
listOf(OperandKind.SLOT, OperandKind.SLOT) listOf(OperandKind.SLOT, OperandKind.SLOT)
@ -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_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_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_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.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.ADD_OBJ, Opcode.SUB_OBJ, Opcode.MUL_OBJ, Opcode.DIV_OBJ, Opcode.MOD_OBJ, Opcode.CONTAINS_OBJ,
Opcode.AND_BOOL, Opcode.OR_BOOL -> Opcode.AND_BOOL, Opcode.OR_BOOL ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*
*/ */
package net.sergeych.lyng.bytecode package net.sergeych.lyng.bytecode
@ -98,6 +99,36 @@ enum class Opcode(val code: Int) {
CMP_NEQ_OBJ(0x6D), CMP_NEQ_OBJ(0x6D),
CMP_REF_EQ_OBJ(0x6E), CMP_REF_EQ_OBJ(0x6E),
CMP_REF_NEQ_OBJ(0x6F), 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), NOT_BOOL(0x70),
AND_BOOL(0x71), AND_BOOL(0x71),

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -73,6 +73,8 @@ data class ObjBool(val value: Boolean) : Obj() {
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder,lynonType: LynonType?): Obj { override suspend fun deserialize(scope: Scope, decoder: LynonDecoder,lynonType: LynonType?): Obj {
return ObjBool(decoder.unpackBoolean()) return ObjBool(decoder.unpackBoolean())
} }
}.apply {
isClosed = true
} }
} }
} }

View File

@ -109,6 +109,7 @@ open class ObjClass(
var isAnonymous: Boolean = false var isAnonymous: Boolean = false
var isAbstract: Boolean = false var isAbstract: Boolean = false
var isClosed: Boolean = false
// Stable identity and simple structural version for PICs // Stable identity and simple structural version for PICs
val classId: Long = ClassIdGen.nextId() val classId: Long = ClassIdGen.nextId()
@ -399,7 +400,16 @@ open class ObjClass(
internal fun fieldSlotMap(): Map<String, FieldSlot> = ensureFieldSlots() internal fun fieldSlotMap(): Map<String, FieldSlot> = ensureFieldSlots()
internal fun fieldRecordForId(fieldId: Int): ObjRecord? { internal fun fieldRecordForId(fieldId: Int): ObjRecord? {
ensureFieldSlots() 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 resolveInstanceMember(name: String): ResolvedMember? = ensureInstanceMemberCache()[name]
internal fun methodSlotCount(): Int { internal fun methodSlotCount(): Int {
@ -423,9 +433,18 @@ open class ObjClass(
if (rec.methodId == methodId) return rec 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 return null
} }
internal fun instanceFieldIdMap(): Map<String, Int> { internal fun instanceFieldIdMap(): Map<String, Int> {
val result = mutableMapOf<String, Int>() val result = mutableMapOf<String, Int>()
for (cls in mro) { for (cls in mro) {
@ -479,7 +498,13 @@ open class ObjClass(
fieldIdMap[name] = existingId fieldIdMap[name] = existingId
return 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 return id
} }
@ -493,7 +518,13 @@ open class ObjClass(
} }
return existingId 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) { if (id >= nextMethodId) {
nextMethodId = id + 1 nextMethodId = id + 1
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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") else -> scope.raiseIllegalState("illegal type code for Int: $lynonType")
} }
}.apply { }.apply {
isClosed = true
addFnDoc( addFnDoc(
name = "toInt", name = "toInt",
doc = "Returns this integer (identity operation).", doc = "Returns this integer (identity operation).",

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.JsonElement
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
import net.sergeych.lyng.Pos
import net.sergeych.lyng.Scope import net.sergeych.lyng.Scope
import net.sergeych.lyng.miniast.addConstDoc import net.sergeych.lyng.miniast.addConstDoc
import net.sergeych.lyng.miniast.addFnDoc 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 = override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
of(decoder.unpackDouble()) of(decoder.unpackDouble())
}.apply { }.apply {
isClosed = true
// roundToInt: number rounded to the nearest integer // roundToInt: number rounded to the nearest integer
addConstDoc( addConstDoc(
name = "roundToInt", name = "roundToInt",

View File

@ -25,8 +25,8 @@ import net.sergeych.lyng.PerfFlags
import net.sergeych.lyng.Pos import net.sergeych.lyng.Pos
import net.sergeych.lyng.RegexCache import net.sergeych.lyng.RegexCache
import net.sergeych.lyng.Scope import net.sergeych.lyng.Scope
import net.sergeych.lyng.requireScope
import net.sergeych.lyng.miniast.* import net.sergeych.lyng.miniast.*
import net.sergeych.lyng.requireScope
import net.sergeych.lynon.LynonDecoder import net.sergeych.lynon.LynonDecoder
import net.sergeych.lynon.LynonEncoder import net.sergeych.lynon.LynonEncoder
import net.sergeych.lynon.LynonType 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 = override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
ObjString(decoder.unpackBinaryData().decodeToString()) ObjString(decoder.unpackBinaryData().decodeToString())
}.apply { }.apply {
isClosed = true
addFnDoc( addFnDoc(
name = "iterator", name = "iterator",
doc = "Iterator over characters of this string.", doc = "Iterator over characters of this string.",

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -187,12 +187,24 @@ class TypesTest {
val base = [1, 2] val base = [1, 2]
acceptInts([...base, 3]) acceptInts([...base, 3])
""".trimIndent()) """.trimIndent())
eval("""
fun acceptReals<T: Real>(xs: List<T>) { }
acceptReals([1.0, 2.0, 3.0])
val base = [1.0, 2.0]
acceptReals([...base, 3.0])
""".trimIndent())
assertFailsWith<net.sergeych.lyng.ScriptError> { assertFailsWith<net.sergeych.lyng.ScriptError> {
eval(""" eval("""
fun acceptInts<T: Int>(xs: List<T>) { } fun acceptInts<T: Int>(xs: List<T>) { }
acceptInts([1, "a"]) acceptInts([1, "a"])
""".trimIndent()) """.trimIndent())
} }
assertFailsWith<net.sergeych.lyng.ScriptError> {
eval("""
fun acceptReals<T: Real>(xs: List<T>) { }
acceptReals([1.0, "a"])
""".trimIndent())
}
} }
@Test @Test

View File

@ -37,6 +37,12 @@
- 2026-02-15 baseline (fused int-compare jumps): 74 ms. - 2026-02-15 baseline (fused int-compare jumps): 74 ms.
- Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'` - Command: `./gradlew :lynglib:jvmTest -Pbenchmarks=true --tests '*NestedRangeBenchmarkTest*'`
- Notes: loop range checks use `JMP_IF_GTE_INT` (no CMP+bool temp). - 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 ### Hypothesis for Native slowdown
- Suspend/virtual dispatch per opcode dominates on K/N, even with no allocations in int ops. - Suspend/virtual dispatch per opcode dominates on K/N, even with no allocations in int ops.

49
notes/vm_fastpath_plan.md Normal file
View File

@ -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*'`