Add bytecode destructuring assignment
This commit is contained in:
parent
780227a229
commit
694d15c69d
@ -36,8 +36,8 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Support `ClassDeclStatement`, `FunctionDeclStatement`, `EnumDeclStatement` in bytecode compilation.
|
- [x] Support `ClassDeclStatement`, `FunctionDeclStatement`, `EnumDeclStatement` in bytecode compilation.
|
||||||
- [x] Keep a mixed execution path for declarations (module bytecode calls statement bodies via `CALL_SLOT`).
|
- [x] Keep a mixed execution path for declarations (module bytecode calls statement bodies via `CALL_SLOT`).
|
||||||
- [x] Ensure module object member refs compile as instance access (not class-scope).
|
- [x] Ensure module object member refs compile as instance access (not class-scope).
|
||||||
- [ ] Step 11: Destructuring assignment bytecode.
|
- [x] Step 11: Destructuring assignment bytecode.
|
||||||
- [ ] Handle `[a, b] = expr` (AssignRef target `ListLiteralRef`) without interpreter fallback.
|
- [x] Handle `[a, b] = expr` (AssignRef target `ListLiteralRef`) without interpreter fallback.
|
||||||
- [ ] Step 12: Optional member assign-ops and inc/dec in bytecode.
|
- [ ] Step 12: Optional member assign-ops and inc/dec in bytecode.
|
||||||
- [ ] Support `a?.b += 1` and `a?.b++` for `FieldRef` targets.
|
- [ ] Support `a?.b += 1` and `a?.b++` for `FieldRef` targets.
|
||||||
- [x] Fix post-inc return value for object slots stored in scope frames.
|
- [x] Fix post-inc return value for object slots stored in scope frames.
|
||||||
|
|||||||
@ -1949,9 +1949,12 @@ class Compiler(
|
|||||||
is CastRef -> containsUnsupportedRef(ref.castValueRef()) || containsUnsupportedRef(ref.castTypeRef())
|
is CastRef -> containsUnsupportedRef(ref.castValueRef()) || containsUnsupportedRef(ref.castTypeRef())
|
||||||
is net.sergeych.lyng.obj.TypeDeclRef -> false
|
is net.sergeych.lyng.obj.TypeDeclRef -> false
|
||||||
is AssignRef -> {
|
is AssignRef -> {
|
||||||
if (ref.target is ListLiteralRef) return true
|
|
||||||
val target = ref.target as? LocalSlotRef
|
val target = ref.target as? LocalSlotRef
|
||||||
(target?.isDelegated == true) || containsUnsupportedRef(ref.value)
|
if (target != null) {
|
||||||
|
(target.isDelegated) || containsUnsupportedRef(ref.value)
|
||||||
|
} else {
|
||||||
|
containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is AssignOpRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
is AssignOpRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
is AssignIfNullRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
is AssignIfNullRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
|
|||||||
@ -1700,6 +1700,15 @@ class BytecodeCompiler(
|
|||||||
updateNameObjClassFromSlot(nameTarget, slot)
|
updateNameObjClassFromSlot(nameTarget, slot)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
val listTarget = ref.target as? ListLiteralRef
|
||||||
|
if (listTarget != null) {
|
||||||
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
|
val valueObj = ensureObjSlot(value)
|
||||||
|
val declId = builder.addConst(BytecodeConst.DestructureAssign(listTarget, callSitePos()))
|
||||||
|
builder.emit(Opcode.ASSIGN_DESTRUCTURE, declId, valueObj.slot)
|
||||||
|
updateSlotType(valueObj.slot, SlotType.OBJ)
|
||||||
|
return CompiledValue(valueObj.slot, SlotType.OBJ)
|
||||||
|
}
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
val target = ref.target
|
val target = ref.target
|
||||||
if (target is ClassScopeMemberRef) {
|
if (target is ClassScopeMemberRef) {
|
||||||
@ -6252,7 +6261,11 @@ class BytecodeCompiler(
|
|||||||
is CastRef -> containsValueFnRef(ref.castValueRef()) || containsValueFnRef(ref.castTypeRef())
|
is CastRef -> containsValueFnRef(ref.castValueRef()) || containsValueFnRef(ref.castTypeRef())
|
||||||
is AssignRef -> {
|
is AssignRef -> {
|
||||||
val target = assignTarget(ref)
|
val target = assignTarget(ref)
|
||||||
(target != null && containsValueFnRef(target)) || containsValueFnRef(assignValue(ref))
|
if (target != null) {
|
||||||
|
containsValueFnRef(target) || containsValueFnRef(assignValue(ref))
|
||||||
|
} else {
|
||||||
|
containsValueFnRef(ref.target) || containsValueFnRef(assignValue(ref))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is AssignOpRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
is AssignOpRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||||
is AssignIfNullRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
is AssignIfNullRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||||
|
|||||||
@ -61,6 +61,10 @@ sealed class BytecodeConst {
|
|||||||
val isTransient: Boolean,
|
val isTransient: Boolean,
|
||||||
val pos: Pos,
|
val pos: Pos,
|
||||||
) : BytecodeConst()
|
) : BytecodeConst()
|
||||||
|
data class DestructureAssign(
|
||||||
|
val pattern: ListLiteralRef,
|
||||||
|
val pos: Pos,
|
||||||
|
) : BytecodeConst()
|
||||||
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
||||||
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,7 +147,8 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||||
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
@ -398,6 +399,7 @@ class CmdBuilder {
|
|||||||
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
||||||
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
||||||
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
||||||
|
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
||||||
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||||
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.CALL_DYNAMIC_MEMBER -> CmdCallDynamicMember(operands[0], operands[1], operands[2], operands[3], operands[4])
|
Opcode.CALL_DYNAMIC_MEMBER -> CmdCallDynamicMember(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||||
|
|||||||
@ -193,6 +193,7 @@ object CmdDisassembler {
|
|||||||
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
|
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdCallDynamicMember -> Opcode.CALL_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallDynamicMember -> Opcode.CALL_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
@ -254,7 +255,8 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||||
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
|
|||||||
@ -1272,7 +1272,26 @@ class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cm
|
|||||||
scope.updateSlotFor(name, immutableRec)
|
scope.updateSlotFor(name, immutableRec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (slot >= frame.fn.scopeSlotCount) {
|
||||||
frame.storeObjResult(slot, ObjVoid)
|
frame.storeObjResult(slot, ObjVoid)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CmdAssignDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||||
|
frame.syncFrameToScope(useRefs = true)
|
||||||
|
}
|
||||||
|
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureAssign
|
||||||
|
?: error("ASSIGN_DESTRUCTURE expects DestructureAssign at $constId")
|
||||||
|
val value = frame.slotToObj(slot)
|
||||||
|
decl.pattern.setAt(decl.pos, frame.ensureScope(), value)
|
||||||
|
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||||
|
frame.syncScopeToFrame()
|
||||||
|
}
|
||||||
|
frame.storeObjResult(slot, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,7 @@ enum class Opcode(val code: Int) {
|
|||||||
CLEAR_PENDING_THROWABLE(0x8F),
|
CLEAR_PENDING_THROWABLE(0x8F),
|
||||||
|
|
||||||
CALL_DIRECT(0x90),
|
CALL_DIRECT(0x90),
|
||||||
|
ASSIGN_DESTRUCTURE(0x91),
|
||||||
CALL_MEMBER_SLOT(0x92),
|
CALL_MEMBER_SLOT(0x92),
|
||||||
CALL_SLOT(0x93),
|
CALL_SLOT(0x93),
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user