Step 24: remove assign scope slot
This commit is contained in:
parent
6aa23e8ef3
commit
dab0b9f165
@ -81,6 +81,9 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Add bytecode ops to bind/get/set delegated locals without scope storage.
|
- [x] Add bytecode ops to bind/get/set delegated locals without scope storage.
|
||||||
- [x] Store delegated locals in frame slots and compile get/set/assign ops with new ops.
|
- [x] Store delegated locals in frame slots and compile get/set/assign ops with new ops.
|
||||||
- [x] Preserve reflection facade by syncing delegated locals into scope only when needed.
|
- [x] Preserve reflection facade by syncing delegated locals into scope only when needed.
|
||||||
|
- [x] Step 24: Remove `ASSIGN_SCOPE_SLOT` now that delegated locals are always frame-backed.
|
||||||
|
- [x] Force delegated locals into local slots (even module) and avoid scope-slot resolution.
|
||||||
|
- [x] Drop opcode/runtime support for `ASSIGN_SCOPE_SLOT`.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@ -1967,7 +1967,7 @@ class Compiler(
|
|||||||
is AssignRef -> {
|
is AssignRef -> {
|
||||||
val target = ref.target as? LocalSlotRef
|
val target = ref.target as? LocalSlotRef
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
(target.isDelegated) || containsUnsupportedRef(ref.value)
|
containsUnsupportedRef(ref.value)
|
||||||
} else {
|
} else {
|
||||||
containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -317,13 +317,7 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots) return null
|
if (!allowLocalSlots) return null
|
||||||
if (ref.isDelegated) {
|
if (ref.isDelegated) {
|
||||||
val mapped = resolveSlot(ref) ?: return null
|
val mapped = resolveSlot(ref) ?: return null
|
||||||
if (mapped < scopeSlotCount) {
|
if (mapped < scopeSlotCount) return null
|
||||||
val addrSlot = ensureScopeAddr(mapped)
|
|
||||||
val local = allocSlot()
|
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, local)
|
|
||||||
updateSlotType(local, SlotType.OBJ)
|
|
||||||
return CompiledValue(local, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
||||||
val local = allocSlot()
|
val local = allocSlot()
|
||||||
builder.emit(Opcode.DELEGATED_GET_LOCAL, mapped, nameId, local)
|
builder.emit(Opcode.DELEGATED_GET_LOCAL, mapped, nameId, local)
|
||||||
@ -1692,13 +1686,9 @@ class BytecodeCompiler(
|
|||||||
if (localTarget.isDelegated) {
|
if (localTarget.isDelegated) {
|
||||||
val slot = resolveSlot(localTarget) ?: return null
|
val slot = resolveSlot(localTarget) ?: return null
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
if (slot >= scopeSlotCount) {
|
if (slot < scopeSlotCount) return null
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(localTarget.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(localTarget.name))
|
||||||
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, value.slot)
|
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, value.slot)
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, value.slot)
|
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
updateSlotType(slot, SlotType.OBJ)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -2011,14 +2001,10 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots) return compileEvalRef(ref)
|
if (!allowLocalSlots) return compileEvalRef(ref)
|
||||||
if (localTarget.isDelegated) {
|
if (localTarget.isDelegated) {
|
||||||
val slot = resolveSlot(localTarget) ?: return null
|
val slot = resolveSlot(localTarget) ?: return null
|
||||||
|
if (slot < scopeSlotCount) return null
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(localTarget.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(localTarget.name))
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
||||||
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
|
||||||
} else {
|
|
||||||
val addrSlot = ensureScopeAddr(slot)
|
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
|
||||||
}
|
|
||||||
updateSlotType(current, SlotType.OBJ)
|
updateSlotType(current, SlotType.OBJ)
|
||||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||||
val rhsObj = ensureObjSlot(rhs)
|
val rhsObj = ensureObjSlot(rhs)
|
||||||
@ -2033,11 +2019,7 @@ class BytecodeCompiler(
|
|||||||
val result = allocSlot()
|
val result = allocSlot()
|
||||||
builder.emit(objOp, current, rhsObj.slot, result)
|
builder.emit(objOp, current, rhsObj.slot, result)
|
||||||
updateSlotType(result, SlotType.OBJ)
|
updateSlotType(result, SlotType.OBJ)
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, result)
|
||||||
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, result)
|
|
||||||
} else {
|
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, result)
|
|
||||||
}
|
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
updateSlotType(slot, SlotType.OBJ)
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
return CompiledValue(result, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
@ -2326,14 +2308,10 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots || !target.isMutable) return null
|
if (!allowLocalSlots || !target.isMutable) return null
|
||||||
if (target.isDelegated) {
|
if (target.isDelegated) {
|
||||||
val slot = resolveSlot(target) ?: return null
|
val slot = resolveSlot(target) ?: return null
|
||||||
|
if (slot < scopeSlotCount) return null
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
||||||
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
|
||||||
} else {
|
|
||||||
val addrSlot = ensureScopeAddr(slot)
|
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
|
||||||
}
|
|
||||||
val nullSlot = allocSlot()
|
val nullSlot = allocSlot()
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
builder.emit(Opcode.CONST_NULL, nullSlot)
|
||||||
val cmpSlot = allocSlot()
|
val cmpSlot = allocSlot()
|
||||||
@ -2347,11 +2325,7 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.MOVE_OBJ, current, resultSlot)
|
builder.emit(Opcode.MOVE_OBJ, current, resultSlot)
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||||
builder.mark(assignLabel)
|
builder.mark(assignLabel)
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, newValue.slot)
|
||||||
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, newValue.slot)
|
|
||||||
} else {
|
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, newValue.slot)
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, newValue.slot, resultSlot)
|
builder.emit(Opcode.MOVE_OBJ, newValue.slot, resultSlot)
|
||||||
builder.mark(endLabel)
|
builder.mark(endLabel)
|
||||||
updateSlotType(resultSlot, SlotType.OBJ)
|
updateSlotType(resultSlot, SlotType.OBJ)
|
||||||
@ -2840,14 +2814,10 @@ class BytecodeCompiler(
|
|||||||
if (!target.isMutable) return null
|
if (!target.isMutable) return null
|
||||||
if (target.isDelegated) {
|
if (target.isDelegated) {
|
||||||
val slot = resolveSlot(target) ?: return null
|
val slot = resolveSlot(target) ?: return null
|
||||||
|
if (slot < scopeSlotCount) return null
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
||||||
builder.emit(Opcode.DELEGATED_GET_LOCAL, slot, nameId, current)
|
|
||||||
} else {
|
|
||||||
val addrSlot = ensureScopeAddr(slot)
|
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
|
||||||
}
|
|
||||||
updateSlotType(current, SlotType.OBJ)
|
updateSlotType(current, SlotType.OBJ)
|
||||||
val oneSlot = allocSlot()
|
val oneSlot = allocSlot()
|
||||||
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
|
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
|
||||||
@ -2857,11 +2827,7 @@ class BytecodeCompiler(
|
|||||||
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
|
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
|
||||||
builder.emit(op, current, oneSlot, result)
|
builder.emit(op, current, oneSlot, result)
|
||||||
updateSlotType(result, SlotType.OBJ)
|
updateSlotType(result, SlotType.OBJ)
|
||||||
if (slot >= scopeSlotCount) {
|
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, result)
|
||||||
builder.emit(Opcode.DELEGATED_SET_LOCAL, slot, nameId, result)
|
|
||||||
} else {
|
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, result)
|
|
||||||
}
|
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
updateSlotType(slot, SlotType.OBJ)
|
||||||
return if (wantResult && ref.isPost) {
|
return if (wantResult && ref.isPost) {
|
||||||
CompiledValue(current, SlotType.OBJ)
|
CompiledValue(current, SlotType.OBJ)
|
||||||
@ -4619,17 +4585,25 @@ class BytecodeCompiler(
|
|||||||
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
||||||
val slotIndex = stmt.slotIndex
|
val slotIndex = stmt.slotIndex
|
||||||
val scopeId = stmt.scopeId ?: 0
|
val scopeId = stmt.scopeId ?: 0
|
||||||
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
|
||||||
val localSlot = if (slotIndex != null) {
|
val localSlot = if (slotIndex != null) {
|
||||||
val key = ScopeSlotKey(scopeId, slotIndex)
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
localSlotIndexByKey[key]?.let { scopeSlotCount + it }
|
localSlotIndexByKey[key]?.let { scopeSlotCount + it }
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
if (allowLocalSlots && !isModuleSlot && localSlot != null) {
|
if (allowLocalSlots && localSlot != null) {
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(stmt.name))
|
if (value.slot != localSlot) {
|
||||||
val accessId = builder.addConst(BytecodeConst.StringVal(if (stmt.isMutable) "Var" else "Val"))
|
emitMove(value, localSlot)
|
||||||
builder.emit(Opcode.BIND_DELEGATE_LOCAL, value.slot, nameId, accessId, localSlot)
|
}
|
||||||
|
val declId = builder.addConst(
|
||||||
|
BytecodeConst.DelegatedDecl(
|
||||||
|
stmt.name,
|
||||||
|
stmt.isMutable,
|
||||||
|
stmt.visibility,
|
||||||
|
stmt.isTransient
|
||||||
|
)
|
||||||
|
)
|
||||||
|
builder.emit(Opcode.DECL_DELEGATED, declId, localSlot)
|
||||||
updateSlotType(localSlot, SlotType.OBJ)
|
updateSlotType(localSlot, SlotType.OBJ)
|
||||||
return CompiledValue(localSlot, SlotType.OBJ)
|
return CompiledValue(localSlot, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
@ -6032,7 +6006,7 @@ class BytecodeCompiler(
|
|||||||
private fun resolveSlot(ref: LocalSlotRef): Int? {
|
private fun resolveSlot(ref: LocalSlotRef): Int? {
|
||||||
loopSlotOverrides[ref.name]?.let { return it }
|
loopSlotOverrides[ref.name]?.let { return it }
|
||||||
val scopeId = refScopeId(ref)
|
val scopeId = refScopeId(ref)
|
||||||
if (isModuleSlot(scopeId, ref.name)) {
|
if (!ref.isDelegated && isModuleSlot(scopeId, ref.name)) {
|
||||||
val key = ScopeSlotKey(scopeId, refSlot(ref))
|
val key = ScopeSlotKey(scopeId, refSlot(ref))
|
||||||
scopeSlotMap[key]?.let { return it }
|
scopeSlotMap[key]?.let { return it }
|
||||||
scopeSlotIndexByName[ref.name]?.let { return it }
|
scopeSlotIndexByName[ref.name]?.let { return it }
|
||||||
@ -6050,6 +6024,13 @@ class BytecodeCompiler(
|
|||||||
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
||||||
return scopeSlotMap[scopeKey]
|
return scopeSlotMap[scopeKey]
|
||||||
}
|
}
|
||||||
|
if (ref.isDelegated) {
|
||||||
|
val localKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
||||||
|
val localIndex = localSlotIndexByKey[localKey]
|
||||||
|
if (localIndex != null) return scopeSlotCount + localIndex
|
||||||
|
val nameIndex = localSlotIndexByName[ref.name]
|
||||||
|
if (nameIndex != null) return scopeSlotCount + nameIndex
|
||||||
|
}
|
||||||
if (forceScopeSlots) {
|
if (forceScopeSlots) {
|
||||||
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
||||||
return scopeSlotMap[scopeKey]
|
return scopeSlotMap[scopeKey]
|
||||||
@ -6236,8 +6217,7 @@ class BytecodeCompiler(
|
|||||||
is DelegatedVarDeclStatement -> {
|
is DelegatedVarDeclStatement -> {
|
||||||
val slotIndex = stmt.slotIndex
|
val slotIndex = stmt.slotIndex
|
||||||
val scopeId = stmt.scopeId ?: 0
|
val scopeId = stmt.scopeId ?: 0
|
||||||
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
if (allowLocalSlots && slotIndex != null) {
|
||||||
if (allowLocalSlots && !forceScopeSlots && slotIndex != null && !isModuleSlot) {
|
|
||||||
val key = ScopeSlotKey(scopeId, slotIndex)
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
declaredLocalKeys.add(key)
|
declaredLocalKeys.add(key)
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
@ -6528,8 +6508,8 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(ref.name)
|
val shouldLocalize = ref.isDelegated || !forceScopeSlots || intLoopVarNames.contains(ref.name)
|
||||||
val isModuleSlot = isModuleSlot(scopeId, ref.name)
|
val isModuleSlot = if (ref.isDelegated) false else isModuleSlot(scopeId, ref.name)
|
||||||
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable, ref.isDelegated)
|
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable, ref.isDelegated)
|
||||||
@ -6577,8 +6557,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNameMap[key] = target.name
|
scopeSlotNameMap[key] = target.name
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(target.name)
|
val shouldLocalize = target.isDelegated || !forceScopeSlots || intLoopVarNames.contains(target.name)
|
||||||
val isModuleSlot = isModuleSlot(scopeId, target.name)
|
val isModuleSlot = if (target.isDelegated) false else isModuleSlot(scopeId, target.name)
|
||||||
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable, target.isDelegated)
|
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable, target.isDelegated)
|
||||||
|
|||||||
@ -138,8 +138,6 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.RESOLVE_SCOPE_SLOT ->
|
Opcode.RESOLVE_SCOPE_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
||||||
Opcode.ASSIGN_SCOPE_SLOT ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
|
||||||
Opcode.DELEGATED_GET_LOCAL ->
|
Opcode.DELEGATED_GET_LOCAL ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.DELEGATED_SET_LOCAL ->
|
Opcode.DELEGATED_SET_LOCAL ->
|
||||||
@ -265,7 +263,6 @@ class CmdBuilder {
|
|||||||
Opcode.THROW -> CmdThrow(operands[0], operands[1])
|
Opcode.THROW -> CmdThrow(operands[0], operands[1])
|
||||||
Opcode.RETHROW_PENDING -> CmdRethrowPending()
|
Opcode.RETHROW_PENDING -> CmdRethrowPending()
|
||||||
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
|
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
|
||||||
Opcode.ASSIGN_SCOPE_SLOT -> CmdAssignScopeSlot(operands[0], operands[1])
|
|
||||||
Opcode.DELEGATED_GET_LOCAL -> CmdDelegatedGetLocal(operands[0], operands[1], operands[2])
|
Opcode.DELEGATED_GET_LOCAL -> CmdDelegatedGetLocal(operands[0], operands[1], operands[2])
|
||||||
Opcode.DELEGATED_SET_LOCAL -> CmdDelegatedSetLocal(operands[0], operands[1], operands[2])
|
Opcode.DELEGATED_SET_LOCAL -> CmdDelegatedSetLocal(operands[0], operands[1], operands[2])
|
||||||
Opcode.BIND_DELEGATE_LOCAL -> CmdBindDelegateLocal(operands[0], operands[1], operands[2], operands[3])
|
Opcode.BIND_DELEGATE_LOCAL -> CmdBindDelegateLocal(operands[0], operands[1], operands[2], operands[3])
|
||||||
|
|||||||
@ -84,7 +84,6 @@ object CmdDisassembler {
|
|||||||
cmd.dst
|
cmd.dst
|
||||||
)
|
)
|
||||||
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
|
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
|
||||||
is CmdAssignScopeSlot -> Opcode.ASSIGN_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.valueSlot)
|
|
||||||
is CmdDelegatedGetLocal -> Opcode.DELEGATED_GET_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.dst)
|
is CmdDelegatedGetLocal -> Opcode.DELEGATED_GET_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.dst)
|
||||||
is CmdDelegatedSetLocal -> Opcode.DELEGATED_SET_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.valueSlot)
|
is CmdDelegatedSetLocal -> Opcode.DELEGATED_SET_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.valueSlot)
|
||||||
is CmdBindDelegateLocal -> Opcode.BIND_DELEGATE_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.accessId, cmd.dst)
|
is CmdBindDelegateLocal -> Opcode.BIND_DELEGATE_LOCAL to intArrayOf(cmd.delegateSlot, cmd.nameId, cmd.accessId, cmd.dst)
|
||||||
@ -247,8 +246,6 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.RESOLVE_SCOPE_SLOT ->
|
Opcode.RESOLVE_SCOPE_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
||||||
Opcode.ASSIGN_SCOPE_SLOT ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
|
||||||
Opcode.DELEGATED_GET_LOCAL ->
|
Opcode.DELEGATED_GET_LOCAL ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.DELEGATED_SET_LOCAL ->
|
Opcode.DELEGATED_SET_LOCAL ->
|
||||||
|
|||||||
@ -358,13 +358,6 @@ class CmdStoreBoolAddr(internal val src: Int, internal val addrSlot: Int) : Cmd(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CmdAssignScopeSlot(internal val scopeSlot: Int, internal val valueSlot: Int) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
frame.assignScopeSlot(scopeSlot, frame.slotToObj(valueSlot))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdDelegatedGetLocal(
|
class CmdDelegatedGetLocal(
|
||||||
internal val delegateSlot: Int,
|
internal val delegateSlot: Int,
|
||||||
internal val nameId: Int,
|
internal val nameId: Int,
|
||||||
@ -2192,16 +2185,6 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun assignScopeSlot(scopeSlot: Int, value: Obj) {
|
|
||||||
ensureScope()
|
|
||||||
val target = scopeTarget(scopeSlot)
|
|
||||||
val index = ensureScopeSlot(target, scopeSlot)
|
|
||||||
val name = fn.scopeSlotNames.getOrNull(scopeSlot)
|
|
||||||
?: target.raiseSymbolNotFound("slot $scopeSlot")
|
|
||||||
val record = target.getSlotRecord(index)
|
|
||||||
target.assign(record, name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getInt(slot: Int): Long {
|
suspend fun getInt(slot: Int): Long {
|
||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toLong()
|
getScopeSlotValue(slot).toLong()
|
||||||
|
|||||||
@ -161,10 +161,9 @@ enum class Opcode(val code: Int) {
|
|||||||
ITER_PUSH(0xBF),
|
ITER_PUSH(0xBF),
|
||||||
ITER_POP(0xC0),
|
ITER_POP(0xC0),
|
||||||
ITER_CANCEL(0xC1),
|
ITER_CANCEL(0xC1),
|
||||||
ASSIGN_SCOPE_SLOT(0xC2),
|
DELEGATED_GET_LOCAL(0xC2),
|
||||||
DELEGATED_GET_LOCAL(0xC3),
|
DELEGATED_SET_LOCAL(0xC3),
|
||||||
DELEGATED_SET_LOCAL(0xC4),
|
BIND_DELEGATE_LOCAL(0xC4),
|
||||||
BIND_DELEGATE_LOCAL(0xC5),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@ -18,10 +18,12 @@
|
|||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import net.sergeych.lyng.Compiler
|
import net.sergeych.lyng.Compiler
|
||||||
import net.sergeych.lyng.ExecutionError
|
import net.sergeych.lyng.ExecutionError
|
||||||
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.Script
|
import net.sergeych.lyng.Script
|
||||||
import net.sergeych.lyng.ScriptError
|
import net.sergeych.lyng.ScriptError
|
||||||
import net.sergeych.lyng.Source
|
import net.sergeych.lyng.Source
|
||||||
import net.sergeych.lyng.eval
|
import net.sergeych.lyng.eval
|
||||||
|
import net.sergeych.lyng.toSource
|
||||||
import net.sergeych.lyng.obj.toInt
|
import net.sergeych.lyng.obj.toInt
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -218,6 +220,29 @@ class BytecodeRecentOpsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun delegatedLocalDisasmUsesDelegateOps() = runTest {
|
||||||
|
val script = """
|
||||||
|
class BoxDelegate(var v) : Delegate {
|
||||||
|
override fun getValue(thisRef: Object, name: String): Object = v
|
||||||
|
override fun setValue(thisRef: Object, name: String, value: Object) { v = value }
|
||||||
|
}
|
||||||
|
fun calc() {
|
||||||
|
var x by BoxDelegate(1)
|
||||||
|
x += 2
|
||||||
|
x++
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
val compiled = Compiler.compile(script.toSource(), Script.defaultImportManager)
|
||||||
|
val scope = Script.defaultImportManager.newModuleAt(Pos.builtIn)
|
||||||
|
compiled.execute(scope)
|
||||||
|
val disasm = scope.disassembleSymbol("calc")
|
||||||
|
assertTrue(disasm.contains("DELEGATED_GET_LOCAL"), disasm)
|
||||||
|
assertTrue(disasm.contains("DELEGATED_SET_LOCAL"), disasm)
|
||||||
|
assertTrue(disasm.contains("DECL_DELEGATED"), disasm)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun unionMemberDispatchSubtype() = runTest {
|
fun unionMemberDispatchSubtype() = runTest {
|
||||||
eval(
|
eval(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user