Add object equality and reference ops to bytecode

This commit is contained in:
sergeych committed 2026-01-25 21:33:28 +03:00
1 parent 9c56cf751b
commit fd1548c86c
7 files changed
+121 -8

No files matched your search

@@ -133,6 +133,7 @@ class BytecodeBuilder {
Opcode.CMP_EQ_INT_REAL, Opcode.CMP_EQ_REAL_INT, Opcode.CMP_LT_INT_REAL, Opcode.CMP_LT_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_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
Opcode.AND_BOOL, Opcode.OR_BOOL ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
@@ -253,6 +253,16 @@ class BytecodeCompiler {
BinOp.GTE -> {
compileCompareGte(a, b, out)
}
BinOp.REF_EQ -> {
if (a.type != SlotType.OBJ || b.type != SlotType.OBJ) return null
builder.emit(Opcode.CMP_REF_EQ_OBJ, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
BinOp.REF_NEQ -> {
if (a.type != SlotType.OBJ || b.type != SlotType.OBJ) return null
builder.emit(Opcode.CMP_REF_NEQ_OBJ, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
BinOp.AND -> {
if (a.type != SlotType.BOOL) return null
builder.emit(Opcode.AND_BOOL, a.slot, b.slot, out)
@@ -336,6 +346,10 @@ class BytecodeCompiler {
builder.emit(Opcode.CMP_EQ_REAL_INT, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
builder.emit(Opcode.CMP_EQ_OBJ, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
else -> null
}
}
@@ -363,6 +377,10 @@ class BytecodeCompiler {
builder.emit(Opcode.CMP_NEQ_REAL_INT, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
builder.emit(Opcode.CMP_NEQ_OBJ, a.slot, b.slot, out)
CompiledValue(out, SlotType.BOOL)
}
else -> null
}
}
@@ -101,6 +101,7 @@ object BytecodeDisassembler {
Opcode.CMP_EQ_INT_REAL, Opcode.CMP_EQ_REAL_INT, Opcode.CMP_LT_INT_REAL, Opcode.CMP_LT_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_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
Opcode.AND_BOOL, Opcode.OR_BOOL ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
@@ -72,14 +72,18 @@ class BytecodeVm {
ip += fn.constIdWidth
val dst = decoder.readSlot(code, ip)
ip += fn.slotWidth
val c = fn.constants[constId] as? BytecodeConst.ObjRef
?: error("CONST_OBJ expects ObjRef at $constId")
val obj = c.value
when (obj) {
is ObjInt -> frame.setInt(dst, obj.value)
is ObjReal -> frame.setReal(dst, obj.value)
is ObjBool -> frame.setBool(dst, obj.value)
else -> frame.setObj(dst, obj)
when (val c = fn.constants[constId]) {
is BytecodeConst.ObjRef -> {
val obj = c.value
when (obj) {
is ObjInt -> frame.setInt(dst, obj.value)
is ObjReal -> frame.setReal(dst, obj.value)
is ObjBool -> frame.setBool(dst, obj.value)
else -> frame.setObj(dst, obj)
}
}
is BytecodeConst.StringVal -> frame.setObj(dst, ObjString(c.value))
else -> error("CONST_OBJ expects ObjRef/StringVal at $constId")
}
}
Opcode.CONST_NULL -> {
@@ -543,6 +547,42 @@ class BytecodeVm {
ip += fn.slotWidth
frame.setBool(dst, frame.getReal(a) != frame.getInt(b).toDouble())
}
Opcode.CMP_EQ_OBJ -> {
val a = decoder.readSlot(code, ip)
ip += fn.slotWidth
val b = decoder.readSlot(code, ip)
ip += fn.slotWidth
val dst = decoder.readSlot(code, ip)
ip += fn.slotWidth
frame.setBool(dst, frame.getObj(a).equals(scope, frame.getObj(b)))
}
Opcode.CMP_NEQ_OBJ -> {
val a = decoder.readSlot(code, ip)
ip += fn.slotWidth
val b = decoder.readSlot(code, ip)
ip += fn.slotWidth
val dst = decoder.readSlot(code, ip)
ip += fn.slotWidth
frame.setBool(dst, !frame.getObj(a).equals(scope, frame.getObj(b)))
}
Opcode.CMP_REF_EQ_OBJ -> {
val a = decoder.readSlot(code, ip)
ip += fn.slotWidth
val b = decoder.readSlot(code, ip)
ip += fn.slotWidth
val dst = decoder.readSlot(code, ip)
ip += fn.slotWidth
frame.setBool(dst, frame.getObj(a) === frame.getObj(b))
}
Opcode.CMP_REF_NEQ_OBJ -> {
val a = decoder.readSlot(code, ip)
ip += fn.slotWidth
val b = decoder.readSlot(code, ip)
ip += fn.slotWidth
val dst = decoder.readSlot(code, ip)
ip += fn.slotWidth
frame.setBool(dst, frame.getObj(a) !== frame.getObj(b))
}
Opcode.NOT_BOOL -> {
val src = decoder.readSlot(code, ip)
ip += fn.slotWidth
@@ -83,6 +83,10 @@ enum class Opcode(val code: Int) {
CMP_GTE_REAL_INT(0x69),
CMP_NEQ_INT_REAL(0x6A),
CMP_NEQ_REAL_INT(0x6B),
CMP_EQ_OBJ(0x6C),
CMP_NEQ_OBJ(0x6D),
CMP_REF_EQ_OBJ(0x6E),
CMP_REF_NEQ_OBJ(0x6F),
NOT_BOOL(0x70),
AND_BOOL(0x71),