Step 27B: bytecode ::class
This commit is contained in:
parent
ac680ceb6c
commit
18278794d6
@ -128,6 +128,7 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [ ] Step 27: Remove interpreter opcodes and constants from bytecode runtime.
|
- [ ] Step 27: Remove interpreter opcodes and constants from bytecode runtime.
|
||||||
- [ ] Delete `BytecodeConst.ValueFn`, `CmdMakeValueFn`, and `MAKE_VALUE_FN` (blocked: some lambdas still fall back to non-bytecode bodies).
|
- [ ] Delete `BytecodeConst.ValueFn`, `CmdMakeValueFn`, and `MAKE_VALUE_FN` (blocked: some lambdas still fall back to non-bytecode bodies).
|
||||||
- [x] Delete `BytecodeConst.StatementVal`, `CmdEvalStmt`, and `EVAL_STMT`.
|
- [x] Delete `BytecodeConst.StatementVal`, `CmdEvalStmt`, and `EVAL_STMT`.
|
||||||
|
- [x] Add bytecode-backed `::class` via `ClassOperatorRef` + `GET_OBJ_CLASS` to avoid ValueFn for class operator.
|
||||||
- [ ] Remove `emitStatementCall`/`emitStatementEval` once unused.
|
- [ ] Remove `emitStatementCall`/`emitStatementEval` once unused.
|
||||||
- [ ] Step 28: Scope as facade only.
|
- [ ] Step 28: Scope as facade only.
|
||||||
- [ ] Audit bytecode execution paths for `Statement.execute` usage and remove remaining calls.
|
- [ ] Audit bytecode execution paths for `Statement.execute` usage and remove remaining calls.
|
||||||
|
|||||||
@ -2044,6 +2044,7 @@ class Compiler(
|
|||||||
is QualifiedThisMethodSlotCallRef -> false
|
is QualifiedThisMethodSlotCallRef -> false
|
||||||
is QualifiedThisFieldSlotRef -> false
|
is QualifiedThisFieldSlotRef -> false
|
||||||
is ClassScopeMemberRef -> false
|
is ClassScopeMemberRef -> false
|
||||||
|
is ClassOperatorRef -> containsUnsupportedRef(ref.target)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3118,9 +3119,7 @@ class Compiler(
|
|||||||
if (t.type != Token.Type.ID) throw ScriptError(t.pos, "Expecting ID after ::")
|
if (t.type != Token.Type.ID) throw ScriptError(t.pos, "Expecting ID after ::")
|
||||||
return when (t.value) {
|
return when (t.value) {
|
||||||
"class" -> {
|
"class" -> {
|
||||||
val ref = ValueFnRef { scope ->
|
val ref = ClassOperatorRef(operand, t.pos)
|
||||||
operand.evalValue(scope).objClass.asReadonly
|
|
||||||
}
|
|
||||||
lambdaReturnTypeByRef[ref] = ObjClassType
|
lambdaReturnTypeByRef[ref] = ObjClassType
|
||||||
ref
|
ref
|
||||||
}
|
}
|
||||||
@ -7247,6 +7246,7 @@ class Compiler(
|
|||||||
decl?.let { resolveClassByName(it.typeName) }
|
decl?.let { resolveClassByName(it.typeName) }
|
||||||
}
|
}
|
||||||
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
||||||
|
is ClassOperatorRef -> lambdaReturnTypeByRef[directRef]
|
||||||
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
||||||
is BinaryOpRef -> inferBinaryOpReturnClass(directRef)
|
is BinaryOpRef -> inferBinaryOpReturnClass(directRef)
|
||||||
is ImplicitThisMethodCallRef -> {
|
is ImplicitThisMethodCallRef -> {
|
||||||
|
|||||||
@ -420,6 +420,14 @@ class BytecodeCompiler(
|
|||||||
CompiledValue(slot, resolved)
|
CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
is ValueFnRef -> compileValueFnRef(ref)
|
is ValueFnRef -> compileValueFnRef(ref)
|
||||||
|
is ClassOperatorRef -> {
|
||||||
|
val target = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
||||||
|
val dst = allocSlot()
|
||||||
|
builder.emit(Opcode.GET_OBJ_CLASS, target.slot, dst)
|
||||||
|
updateSlotType(dst, SlotType.OBJ)
|
||||||
|
slotObjClass[dst] = ObjClassType
|
||||||
|
CompiledValue(dst, SlotType.OBJ)
|
||||||
|
}
|
||||||
is ListLiteralRef -> compileListLiteral(ref)
|
is ListLiteralRef -> compileListLiteral(ref)
|
||||||
is MapLiteralRef -> compileMapLiteral(ref)
|
is MapLiteralRef -> compileMapLiteral(ref)
|
||||||
is ThisMethodSlotCallRef -> compileThisMethodSlotCall(ref)
|
is ThisMethodSlotCallRef -> compileThisMethodSlotCall(ref)
|
||||||
|
|||||||
@ -129,7 +129,7 @@ class CmdBuilder {
|
|||||||
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.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.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,
|
||||||
Opcode.ASSERT_IS ->
|
Opcode.ASSERT_IS ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
@ -258,6 +258,7 @@ class CmdBuilder {
|
|||||||
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.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.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])
|
||||||
Opcode.LOAD_THIS -> CmdLoadThis(operands[0])
|
Opcode.LOAD_THIS -> CmdLoadThis(operands[0])
|
||||||
Opcode.LOAD_THIS_VARIANT -> CmdLoadThisVariant(operands[0], operands[1])
|
Opcode.LOAD_THIS_VARIANT -> CmdLoadThisVariant(operands[0], operands[1])
|
||||||
|
|||||||
@ -90,6 +90,7 @@ object CmdDisassembler {
|
|||||||
is CmdMakeLambda -> Opcode.MAKE_LAMBDA_FN to intArrayOf(cmd.id, cmd.dst)
|
is CmdMakeLambda -> Opcode.MAKE_LAMBDA_FN to intArrayOf(cmd.id, cmd.dst)
|
||||||
is CmdBoxObj -> Opcode.BOX_OBJ to intArrayOf(cmd.src, cmd.dst)
|
is CmdBoxObj -> Opcode.BOX_OBJ to intArrayOf(cmd.src, cmd.dst)
|
||||||
is CmdObjToBool -> Opcode.OBJ_TO_BOOL to intArrayOf(cmd.src, cmd.dst)
|
is CmdObjToBool -> Opcode.OBJ_TO_BOOL to intArrayOf(cmd.src, cmd.dst)
|
||||||
|
is CmdGetObjClass -> Opcode.GET_OBJ_CLASS to intArrayOf(cmd.src, cmd.dst)
|
||||||
is CmdCheckIs -> Opcode.CHECK_IS to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
is CmdCheckIs -> Opcode.CHECK_IS to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
||||||
is CmdAssertIs -> Opcode.ASSERT_IS to intArrayOf(cmd.objSlot, cmd.typeSlot)
|
is CmdAssertIs -> Opcode.ASSERT_IS to intArrayOf(cmd.objSlot, cmd.typeSlot)
|
||||||
is CmdMakeQualifiedView -> Opcode.MAKE_QUALIFIED_VIEW to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
is CmdMakeQualifiedView -> Opcode.MAKE_QUALIFIED_VIEW to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
||||||
@ -256,7 +257,7 @@ object CmdDisassembler {
|
|||||||
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
Opcode.INT_TO_REAL, Opcode.REAL_TO_INT, Opcode.BOOL_TO_INT, Opcode.INT_TO_BOOL,
|
||||||
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.OBJ_TO_BOOL, Opcode.ASSERT_IS ->
|
Opcode.OBJ_TO_BOOL, Opcode.GET_OBJ_CLASS, Opcode.ASSERT_IS ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
|
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
|
|||||||
@ -214,6 +214,14 @@ class CmdObjToBool(internal val src: Int, internal val dst: Int) : Cmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CmdGetObjClass(internal val src: Int, internal val dst: Int) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val cls = frame.slotToObj(src).objClass
|
||||||
|
frame.setObj(dst, cls)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CmdCheckIs(internal val objSlot: Int, internal val typeSlot: Int, internal val dst: Int) : Cmd() {
|
class CmdCheckIs(internal val objSlot: Int, internal val typeSlot: Int, internal val dst: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val obj = frame.slotToObj(objSlot)
|
val obj = frame.slotToObj(objSlot)
|
||||||
|
|||||||
@ -43,6 +43,7 @@ enum class Opcode(val code: Int) {
|
|||||||
ASSERT_IS(0x16),
|
ASSERT_IS(0x16),
|
||||||
MAKE_QUALIFIED_VIEW(0x17),
|
MAKE_QUALIFIED_VIEW(0x17),
|
||||||
MAKE_LAMBDA_FN(0x18),
|
MAKE_LAMBDA_FN(0x18),
|
||||||
|
GET_OBJ_CLASS(0x19),
|
||||||
|
|
||||||
ADD_INT(0x20),
|
ADD_INT(0x20),
|
||||||
SUB_INT(0x21),
|
SUB_INT(0x21),
|
||||||
|
|||||||
@ -78,6 +78,13 @@ open class ValueFnRef(private val fn: suspend (Scope) -> ObjRecord) : ObjRef {
|
|||||||
override suspend fun get(scope: Scope): ObjRecord = fn(scope)
|
override suspend fun get(scope: Scope): ObjRecord = fn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compile-time supported ::class operator reference. */
|
||||||
|
class ClassOperatorRef(val target: ObjRef, val pos: Pos) : ObjRef {
|
||||||
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
|
return target.evalValue(scope).objClass.asReadonly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Unary operations supported by ObjRef. */
|
/** Unary operations supported by ObjRef. */
|
||||||
enum class UnaryOp { NOT, NEGATE, BITNOT }
|
enum class UnaryOp { NOT, NEGATE, BITNOT }
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user