Step 23: frame-based delegated locals
This commit is contained in:
parent
c035b4c34c
commit
6aa23e8ef3
@ -77,6 +77,10 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Support reads/writes/assign-ops/inc/dec for delegated locals (`LocalSlotRef.isDelegated`) in `BytecodeCompiler`.
|
- [x] Support reads/writes/assign-ops/inc/dec for delegated locals (`LocalSlotRef.isDelegated`) in `BytecodeCompiler`.
|
||||||
- [x] Remove `containsDelegatedRefs` guard once delegated locals are bytecode-safe.
|
- [x] Remove `containsDelegatedRefs` guard once delegated locals are bytecode-safe.
|
||||||
- [x] Add JVM tests that use delegated locals inside bytecode-compiled functions.
|
- [x] Add JVM tests that use delegated locals inside bytecode-compiled functions.
|
||||||
|
- [x] Step 23: Refactor delegated locals to keep delegate objects in frame slots.
|
||||||
|
- [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] Preserve reflection facade by syncing delegated locals into scope only when needed.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@ -7985,12 +7985,17 @@ class Compiler(
|
|||||||
) {
|
) {
|
||||||
if (isDelegate) {
|
if (isDelegate) {
|
||||||
val initExpr = initialExpression ?: throw ScriptError(start, "Delegate must be initialized")
|
val initExpr = initialExpression ?: throw ScriptError(start, "Delegate must be initialized")
|
||||||
|
val slotPlan = slotPlanStack.lastOrNull()
|
||||||
|
val slotIndex = slotPlan?.slots?.get(name)?.index
|
||||||
|
val scopeId = slotPlan?.id
|
||||||
return DelegatedVarDeclStatement(
|
return DelegatedVarDeclStatement(
|
||||||
name,
|
name,
|
||||||
isMutable,
|
isMutable,
|
||||||
visibility,
|
visibility,
|
||||||
initExpr,
|
initExpr,
|
||||||
isTransient,
|
isTransient,
|
||||||
|
slotIndex,
|
||||||
|
scopeId,
|
||||||
start
|
start
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,8 @@ class DelegatedVarDeclStatement(
|
|||||||
val visibility: Visibility,
|
val visibility: Visibility,
|
||||||
val initializer: Statement,
|
val initializer: Statement,
|
||||||
val isTransient: Boolean,
|
val isTransient: Boolean,
|
||||||
|
val slotIndex: Int?,
|
||||||
|
val scopeId: Int?,
|
||||||
private val startPos: Pos,
|
private val startPos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|||||||
@ -48,13 +48,14 @@ class BytecodeCompiler(
|
|||||||
private val scopeSlotIndexByName = LinkedHashMap<String, Int>()
|
private val scopeSlotIndexByName = LinkedHashMap<String, Int>()
|
||||||
private val pendingScopeNameRefs = LinkedHashSet<String>()
|
private val pendingScopeNameRefs = LinkedHashSet<String>()
|
||||||
private val addrSlotByScopeSlot = LinkedHashMap<Int, Int>()
|
private val addrSlotByScopeSlot = LinkedHashMap<Int, Int>()
|
||||||
private data class LocalSlotInfo(val name: String, val isMutable: Boolean)
|
private data class LocalSlotInfo(val name: String, val isMutable: Boolean, val isDelegated: Boolean)
|
||||||
private val localSlotInfoMap = LinkedHashMap<ScopeSlotKey, LocalSlotInfo>()
|
private val localSlotInfoMap = LinkedHashMap<ScopeSlotKey, LocalSlotInfo>()
|
||||||
private val localSlotIndexByKey = LinkedHashMap<ScopeSlotKey, Int>()
|
private val localSlotIndexByKey = LinkedHashMap<ScopeSlotKey, Int>()
|
||||||
private val localSlotIndexByName = LinkedHashMap<String, Int>()
|
private val localSlotIndexByName = LinkedHashMap<String, Int>()
|
||||||
private val loopSlotOverrides = LinkedHashMap<String, Int>()
|
private val loopSlotOverrides = LinkedHashMap<String, Int>()
|
||||||
private var localSlotNames = emptyArray<String?>()
|
private var localSlotNames = emptyArray<String?>()
|
||||||
private var localSlotMutables = BooleanArray(0)
|
private var localSlotMutables = BooleanArray(0)
|
||||||
|
private var localSlotDelegated = BooleanArray(0)
|
||||||
private val declaredLocalKeys = LinkedHashSet<ScopeSlotKey>()
|
private val declaredLocalKeys = LinkedHashSet<ScopeSlotKey>()
|
||||||
private val localRangeRefs = LinkedHashMap<ScopeSlotKey, RangeRef>()
|
private val localRangeRefs = LinkedHashMap<ScopeSlotKey, RangeRef>()
|
||||||
private val slotTypes = mutableMapOf<Int, SlotType>()
|
private val slotTypes = mutableMapOf<Int, SlotType>()
|
||||||
@ -98,7 +99,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is BlockStatement -> compileBlock(name, stmt)
|
is BlockStatement -> compileBlock(name, stmt)
|
||||||
@ -117,7 +119,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is DestructuringVarDeclStatement -> {
|
is DestructuringVarDeclStatement -> {
|
||||||
@ -133,7 +136,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.ThrowStatement -> compileThrowStatement(name, stmt)
|
is net.sergeych.lyng.ThrowStatement -> compileThrowStatement(name, stmt)
|
||||||
@ -151,7 +155,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> {
|
is net.sergeych.lyng.ClassDeclStatement -> {
|
||||||
@ -167,7 +172,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> {
|
is net.sergeych.lyng.FunctionDeclStatement -> {
|
||||||
@ -183,7 +189,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> {
|
is net.sergeych.lyng.EnumDeclStatement -> {
|
||||||
@ -199,7 +206,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.NopStatement -> {
|
is net.sergeych.lyng.NopStatement -> {
|
||||||
@ -216,7 +224,8 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
|
localSlotDelegated
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
@ -235,8 +244,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileExtensionPropertyDecl(
|
private fun compileExtensionPropertyDecl(
|
||||||
@ -256,8 +266,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compileExpression(name: String, stmt: ExpressionStatement): CmdFunction? {
|
fun compileExpression(name: String, stmt: ExpressionStatement): CmdFunction? {
|
||||||
@ -274,8 +285,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class CompiledValue(val slot: Int, val type: SlotType)
|
private data class CompiledValue(val slot: Int, val type: SlotType)
|
||||||
@ -312,8 +324,11 @@ class BytecodeCompiler(
|
|||||||
updateSlotType(local, SlotType.OBJ)
|
updateSlotType(local, SlotType.OBJ)
|
||||||
return CompiledValue(local, SlotType.OBJ)
|
return CompiledValue(local, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
updateSlotType(mapped, SlotType.OBJ)
|
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
||||||
return CompiledValue(mapped, SlotType.OBJ)
|
val local = allocSlot()
|
||||||
|
builder.emit(Opcode.DELEGATED_GET_LOCAL, mapped, nameId, local)
|
||||||
|
updateSlotType(local, SlotType.OBJ)
|
||||||
|
return CompiledValue(local, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
if (ref.name.isEmpty()) return null
|
if (ref.name.isEmpty()) return null
|
||||||
if (ref.captureOwnerScopeId == null && refScopeId(ref) == 0) {
|
if (ref.captureOwnerScopeId == null && refScopeId(ref) == 0) {
|
||||||
@ -1676,8 +1691,13 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots) return null
|
if (!allowLocalSlots) return null
|
||||||
if (localTarget.isDelegated) {
|
if (localTarget.isDelegated) {
|
||||||
val slot = resolveSlot(localTarget) ?: return null
|
val slot = resolveSlot(localTarget) ?: return null
|
||||||
if (slot >= scopeSlotCount) return null
|
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
|
if (slot >= scopeSlotCount) {
|
||||||
|
val nameId = builder.addConst(BytecodeConst.StringVal(localTarget.name))
|
||||||
|
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)
|
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, value.slot)
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
updateSlotType(slot, SlotType.OBJ)
|
||||||
return value
|
return value
|
||||||
@ -1991,10 +2011,14 @@ 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 addrSlot = ensureScopeAddr(slot)
|
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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)
|
||||||
@ -2009,7 +2033,11 @@ 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)
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, result)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
@ -2298,10 +2326,14 @@ 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 addrSlot = ensureScopeAddr(slot)
|
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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()
|
||||||
@ -2315,7 +2347,11 @@ 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)
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, newValue.slot)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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)
|
||||||
@ -2804,10 +2840,14 @@ 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 addrSlot = ensureScopeAddr(slot)
|
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.LOAD_OBJ_ADDR, addrSlot, current)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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))
|
||||||
@ -2817,7 +2857,11 @@ 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)
|
||||||
builder.emit(Opcode.ASSIGN_SCOPE_SLOT, slot, result)
|
if (slot >= scopeSlotCount) {
|
||||||
|
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)
|
||||||
@ -3930,8 +3974,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileForIn(name: String, stmt: net.sergeych.lyng.ForInStatement): CmdFunction? {
|
private fun compileForIn(name: String, stmt: net.sergeych.lyng.ForInStatement): CmdFunction? {
|
||||||
@ -3947,8 +3992,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileWhile(name: String, stmt: net.sergeych.lyng.WhileStatement): CmdFunction? {
|
private fun compileWhile(name: String, stmt: net.sergeych.lyng.WhileStatement): CmdFunction? {
|
||||||
@ -3965,8 +4011,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileDoWhile(name: String, stmt: net.sergeych.lyng.DoWhileStatement): CmdFunction? {
|
private fun compileDoWhile(name: String, stmt: net.sergeych.lyng.DoWhileStatement): CmdFunction? {
|
||||||
@ -3983,8 +4030,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileBlock(name: String, stmt: BlockStatement): CmdFunction? {
|
private fun compileBlock(name: String, stmt: BlockStatement): CmdFunction? {
|
||||||
@ -4004,8 +4052,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileVarDecl(name: String, stmt: VarDeclStatement): CmdFunction? {
|
private fun compileVarDecl(name: String, stmt: VarDeclStatement): CmdFunction? {
|
||||||
@ -4021,8 +4070,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileStatementValue(stmt: Statement): CompiledValue? {
|
private fun compileStatementValue(stmt: Statement): CompiledValue? {
|
||||||
@ -4431,8 +4481,9 @@ class BytecodeCompiler(
|
|||||||
scopeSlotNames,
|
scopeSlotNames,
|
||||||
scopeSlotIsModule,
|
scopeSlotIsModule,
|
||||||
localSlotNames,
|
localSlotNames,
|
||||||
localSlotMutables
|
localSlotMutables,
|
||||||
)
|
localSlotDelegated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
||||||
@ -4566,6 +4617,22 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
private fun emitDelegatedVarDecl(stmt: DelegatedVarDeclStatement): CompiledValue? {
|
private fun emitDelegatedVarDecl(stmt: DelegatedVarDeclStatement): CompiledValue? {
|
||||||
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
||||||
|
val slotIndex = stmt.slotIndex
|
||||||
|
val scopeId = stmt.scopeId ?: 0
|
||||||
|
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
||||||
|
val localSlot = if (slotIndex != null) {
|
||||||
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
|
localSlotIndexByKey[key]?.let { scopeSlotCount + it }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (allowLocalSlots && !isModuleSlot && localSlot != null) {
|
||||||
|
val nameId = builder.addConst(BytecodeConst.StringVal(stmt.name))
|
||||||
|
val accessId = builder.addConst(BytecodeConst.StringVal(if (stmt.isMutable) "Var" else "Val"))
|
||||||
|
builder.emit(Opcode.BIND_DELEGATE_LOCAL, value.slot, nameId, accessId, localSlot)
|
||||||
|
updateSlotType(localSlot, SlotType.OBJ)
|
||||||
|
return CompiledValue(localSlot, SlotType.OBJ)
|
||||||
|
}
|
||||||
val declId = builder.addConst(
|
val declId = builder.addConst(
|
||||||
BytecodeConst.DelegatedDecl(
|
BytecodeConst.DelegatedDecl(
|
||||||
stmt.name,
|
stmt.name,
|
||||||
@ -6026,6 +6093,7 @@ class BytecodeCompiler(
|
|||||||
pendingScopeNameRefs.clear()
|
pendingScopeNameRefs.clear()
|
||||||
localSlotNames = emptyArray()
|
localSlotNames = emptyArray()
|
||||||
localSlotMutables = BooleanArray(0)
|
localSlotMutables = BooleanArray(0)
|
||||||
|
localSlotDelegated = BooleanArray(0)
|
||||||
declaredLocalKeys.clear()
|
declaredLocalKeys.clear()
|
||||||
localRangeRefs.clear()
|
localRangeRefs.clear()
|
||||||
intLoopVarNames.clear()
|
intLoopVarNames.clear()
|
||||||
@ -6072,6 +6140,7 @@ class BytecodeCompiler(
|
|||||||
if (allowLocalSlots && localSlotInfoMap.isNotEmpty()) {
|
if (allowLocalSlots && localSlotInfoMap.isNotEmpty()) {
|
||||||
val names = ArrayList<String?>(localSlotInfoMap.size)
|
val names = ArrayList<String?>(localSlotInfoMap.size)
|
||||||
val mutables = BooleanArray(localSlotInfoMap.size)
|
val mutables = BooleanArray(localSlotInfoMap.size)
|
||||||
|
val delegated = BooleanArray(localSlotInfoMap.size)
|
||||||
var index = 0
|
var index = 0
|
||||||
for ((key, info) in localSlotInfoMap) {
|
for ((key, info) in localSlotInfoMap) {
|
||||||
localSlotIndexByKey[key] = index
|
localSlotIndexByKey[key] = index
|
||||||
@ -6080,10 +6149,12 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
names.add(info.name)
|
names.add(info.name)
|
||||||
mutables[index] = info.isMutable
|
mutables[index] = info.isMutable
|
||||||
|
delegated[index] = info.isDelegated
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
localSlotNames = names.toTypedArray()
|
localSlotNames = names.toTypedArray()
|
||||||
localSlotMutables = mutables
|
localSlotMutables = mutables
|
||||||
|
localSlotDelegated = delegated
|
||||||
}
|
}
|
||||||
if (scopeSlotCount > 0) {
|
if (scopeSlotCount > 0) {
|
||||||
for ((key, index) in scopeSlotMap) {
|
for ((key, index) in scopeSlotMap) {
|
||||||
@ -6144,7 +6215,7 @@ class BytecodeCompiler(
|
|||||||
val key = ScopeSlotKey(scopeId, slotIndex)
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
declaredLocalKeys.add(key)
|
declaredLocalKeys.add(key)
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(stmt.name, stmt.isMutable)
|
localSlotInfoMap[key] = LocalSlotInfo(stmt.name, stmt.isMutable, isDelegated = false)
|
||||||
}
|
}
|
||||||
if (!stmt.isMutable) {
|
if (!stmt.isMutable) {
|
||||||
extractDeclaredRange(stmt.initializer)?.let { range ->
|
extractDeclaredRange(stmt.initializer)?.let { range ->
|
||||||
@ -6163,6 +6234,24 @@ class BytecodeCompiler(
|
|||||||
stmt.initializer?.let { collectScopeSlots(it) }
|
stmt.initializer?.let { collectScopeSlots(it) }
|
||||||
}
|
}
|
||||||
is DelegatedVarDeclStatement -> {
|
is DelegatedVarDeclStatement -> {
|
||||||
|
val slotIndex = stmt.slotIndex
|
||||||
|
val scopeId = stmt.scopeId ?: 0
|
||||||
|
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
||||||
|
if (allowLocalSlots && !forceScopeSlots && slotIndex != null && !isModuleSlot) {
|
||||||
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
|
declaredLocalKeys.add(key)
|
||||||
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
|
localSlotInfoMap[key] = LocalSlotInfo(stmt.name, stmt.isMutable, isDelegated = true)
|
||||||
|
}
|
||||||
|
} else if (slotIndex != null) {
|
||||||
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
|
if (!scopeSlotMap.containsKey(key)) {
|
||||||
|
scopeSlotMap[key] = scopeSlotMap.size
|
||||||
|
}
|
||||||
|
if (!scopeSlotNameMap.containsKey(key)) {
|
||||||
|
scopeSlotNameMap[key] = stmt.name
|
||||||
|
}
|
||||||
|
}
|
||||||
collectScopeSlots(stmt.initializer)
|
collectScopeSlots(stmt.initializer)
|
||||||
}
|
}
|
||||||
is IfStatement -> {
|
is IfStatement -> {
|
||||||
@ -6441,9 +6530,9 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(ref.name)
|
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(ref.name)
|
||||||
val isModuleSlot = isModuleSlot(scopeId, ref.name)
|
val isModuleSlot = isModuleSlot(scopeId, ref.name)
|
||||||
if (allowLocalSlots && !ref.isDelegated && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable)
|
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable, ref.isDelegated)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -6490,9 +6579,9 @@ class BytecodeCompiler(
|
|||||||
} else {
|
} else {
|
||||||
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(target.name)
|
val shouldLocalize = !forceScopeSlots || intLoopVarNames.contains(target.name)
|
||||||
val isModuleSlot = isModuleSlot(scopeId, target.name)
|
val isModuleSlot = isModuleSlot(scopeId, target.name)
|
||||||
if (allowLocalSlots && !target.isDelegated && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable)
|
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable, target.isDelegated)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!scopeSlotMap.containsKey(key)) {
|
if (!scopeSlotMap.containsKey(key)) {
|
||||||
|
|||||||
@ -68,7 +68,8 @@ class CmdBuilder {
|
|||||||
scopeSlotNames: Array<String?> = emptyArray(),
|
scopeSlotNames: Array<String?> = emptyArray(),
|
||||||
scopeSlotIsModule: BooleanArray = BooleanArray(0),
|
scopeSlotIsModule: BooleanArray = BooleanArray(0),
|
||||||
localSlotNames: Array<String?> = emptyArray(),
|
localSlotNames: Array<String?> = emptyArray(),
|
||||||
localSlotMutables: BooleanArray = BooleanArray(0)
|
localSlotMutables: BooleanArray = BooleanArray(0),
|
||||||
|
localSlotDelegated: BooleanArray = BooleanArray(0)
|
||||||
): CmdFunction {
|
): CmdFunction {
|
||||||
val scopeSlotCount = scopeSlotIndices.size
|
val scopeSlotCount = scopeSlotIndices.size
|
||||||
require(scopeSlotNames.isEmpty() || scopeSlotNames.size == scopeSlotCount) {
|
require(scopeSlotNames.isEmpty() || scopeSlotNames.size == scopeSlotCount) {
|
||||||
@ -78,6 +79,7 @@ class CmdBuilder {
|
|||||||
"scope slot module mapping size mismatch"
|
"scope slot module mapping size mismatch"
|
||||||
}
|
}
|
||||||
require(localSlotNames.size == localSlotMutables.size) { "local slot metadata size mismatch" }
|
require(localSlotNames.size == localSlotMutables.size) { "local slot metadata size mismatch" }
|
||||||
|
require(localSlotNames.size == localSlotDelegated.size) { "local slot delegation size mismatch" }
|
||||||
val labelIps = mutableMapOf<Label, Int>()
|
val labelIps = mutableMapOf<Label, Int>()
|
||||||
for ((label, idx) in labelPositions) {
|
for ((label, idx) in labelPositions) {
|
||||||
labelIps[label] = idx
|
labelIps[label] = idx
|
||||||
@ -111,6 +113,7 @@ class CmdBuilder {
|
|||||||
scopeSlotIsModule = if (scopeSlotIsModule.isEmpty()) BooleanArray(scopeSlotCount) else scopeSlotIsModule,
|
scopeSlotIsModule = if (scopeSlotIsModule.isEmpty()) BooleanArray(scopeSlotCount) else scopeSlotIsModule,
|
||||||
localSlotNames = localSlotNames,
|
localSlotNames = localSlotNames,
|
||||||
localSlotMutables = localSlotMutables,
|
localSlotMutables = localSlotMutables,
|
||||||
|
localSlotDelegated = localSlotDelegated,
|
||||||
constants = constPool.toList(),
|
constants = constPool.toList(),
|
||||||
cmds = cmds.toTypedArray(),
|
cmds = cmds.toTypedArray(),
|
||||||
posByIp = posByInstr.toTypedArray()
|
posByIp = posByInstr.toTypedArray()
|
||||||
@ -137,6 +140,12 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
||||||
Opcode.ASSIGN_SCOPE_SLOT ->
|
Opcode.ASSIGN_SCOPE_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
|
Opcode.DELEGATED_GET_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
|
Opcode.DELEGATED_SET_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
|
Opcode.BIND_DELEGATE_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.LOAD_OBJ_ADDR, Opcode.LOAD_INT_ADDR, Opcode.LOAD_REAL_ADDR, Opcode.LOAD_BOOL_ADDR ->
|
Opcode.LOAD_OBJ_ADDR, Opcode.LOAD_INT_ADDR, Opcode.LOAD_REAL_ADDR, Opcode.LOAD_BOOL_ADDR ->
|
||||||
listOf(OperandKind.ADDR, OperandKind.SLOT)
|
listOf(OperandKind.ADDR, OperandKind.SLOT)
|
||||||
Opcode.STORE_OBJ_ADDR, Opcode.STORE_INT_ADDR, Opcode.STORE_REAL_ADDR, Opcode.STORE_BOOL_ADDR ->
|
Opcode.STORE_OBJ_ADDR, Opcode.STORE_INT_ADDR, Opcode.STORE_REAL_ADDR, Opcode.STORE_BOOL_ADDR ->
|
||||||
@ -257,6 +266,9 @@ class CmdBuilder {
|
|||||||
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.ASSIGN_SCOPE_SLOT -> CmdAssignScopeSlot(operands[0], operands[1])
|
||||||
|
Opcode.DELEGATED_GET_LOCAL -> CmdDelegatedGetLocal(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.LOAD_OBJ_ADDR -> CmdLoadObjAddr(operands[0], operands[1])
|
Opcode.LOAD_OBJ_ADDR -> CmdLoadObjAddr(operands[0], operands[1])
|
||||||
Opcode.STORE_OBJ_ADDR -> CmdStoreObjAddr(operands[0], operands[1])
|
Opcode.STORE_OBJ_ADDR -> CmdStoreObjAddr(operands[0], operands[1])
|
||||||
Opcode.LOAD_INT_ADDR -> CmdLoadIntAddr(operands[0], operands[1])
|
Opcode.LOAD_INT_ADDR -> CmdLoadIntAddr(operands[0], operands[1])
|
||||||
|
|||||||
@ -85,6 +85,9 @@ object CmdDisassembler {
|
|||||||
)
|
)
|
||||||
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 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 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 CmdLoadObjAddr -> Opcode.LOAD_OBJ_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
is CmdLoadObjAddr -> Opcode.LOAD_OBJ_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
||||||
is CmdStoreObjAddr -> Opcode.STORE_OBJ_ADDR to intArrayOf(cmd.src, cmd.addrSlot)
|
is CmdStoreObjAddr -> Opcode.STORE_OBJ_ADDR to intArrayOf(cmd.src, cmd.addrSlot)
|
||||||
is CmdLoadIntAddr -> Opcode.LOAD_INT_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
is CmdLoadIntAddr -> Opcode.LOAD_INT_ADDR to intArrayOf(cmd.addrSlot, cmd.dst)
|
||||||
@ -246,6 +249,12 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
listOf(OperandKind.SLOT, OperandKind.ADDR)
|
||||||
Opcode.ASSIGN_SCOPE_SLOT ->
|
Opcode.ASSIGN_SCOPE_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||||
|
Opcode.DELEGATED_GET_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
|
Opcode.DELEGATED_SET_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
|
Opcode.BIND_DELEGATE_LOCAL ->
|
||||||
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.LOAD_OBJ_ADDR, Opcode.LOAD_INT_ADDR, Opcode.LOAD_REAL_ADDR, Opcode.LOAD_BOOL_ADDR ->
|
Opcode.LOAD_OBJ_ADDR, Opcode.LOAD_INT_ADDR, Opcode.LOAD_REAL_ADDR, Opcode.LOAD_BOOL_ADDR ->
|
||||||
listOf(OperandKind.ADDR, OperandKind.SLOT)
|
listOf(OperandKind.ADDR, OperandKind.SLOT)
|
||||||
Opcode.STORE_OBJ_ADDR, Opcode.STORE_INT_ADDR, Opcode.STORE_REAL_ADDR, Opcode.STORE_BOOL_ADDR ->
|
Opcode.STORE_OBJ_ADDR, Opcode.STORE_INT_ADDR, Opcode.STORE_REAL_ADDR, Opcode.STORE_BOOL_ADDR ->
|
||||||
|
|||||||
@ -28,6 +28,7 @@ data class CmdFunction(
|
|||||||
val scopeSlotIsModule: BooleanArray,
|
val scopeSlotIsModule: BooleanArray,
|
||||||
val localSlotNames: Array<String?>,
|
val localSlotNames: Array<String?>,
|
||||||
val localSlotMutables: BooleanArray,
|
val localSlotMutables: BooleanArray,
|
||||||
|
val localSlotDelegated: BooleanArray,
|
||||||
val constants: List<BytecodeConst>,
|
val constants: List<BytecodeConst>,
|
||||||
val cmds: Array<Cmd>,
|
val cmds: Array<Cmd>,
|
||||||
val posByIp: Array<net.sergeych.lyng.Pos?>,
|
val posByIp: Array<net.sergeych.lyng.Pos?>,
|
||||||
@ -37,6 +38,7 @@ data class CmdFunction(
|
|||||||
require(scopeSlotNames.size == scopeSlotCount) { "scopeSlotNames size mismatch" }
|
require(scopeSlotNames.size == scopeSlotCount) { "scopeSlotNames size mismatch" }
|
||||||
require(scopeSlotIsModule.size == scopeSlotCount) { "scopeSlotIsModule size mismatch" }
|
require(scopeSlotIsModule.size == scopeSlotCount) { "scopeSlotIsModule size mismatch" }
|
||||||
require(localSlotNames.size == localSlotMutables.size) { "localSlot metadata size mismatch" }
|
require(localSlotNames.size == localSlotMutables.size) { "localSlot metadata size mismatch" }
|
||||||
|
require(localSlotNames.size == localSlotDelegated.size) { "localSlot delegation size mismatch" }
|
||||||
require(localSlotNames.size <= localCount) { "localSlotNames exceed localCount" }
|
require(localSlotNames.size <= localCount) { "localSlotNames exceed localCount" }
|
||||||
require(addrCount >= 0) { "addrCount must be non-negative" }
|
require(addrCount >= 0) { "addrCount must be non-negative" }
|
||||||
if (posByIp.isNotEmpty()) {
|
if (posByIp.isNotEmpty()) {
|
||||||
|
|||||||
@ -365,6 +365,67 @@ class CmdAssignScopeSlot(internal val scopeSlot: Int, internal val valueSlot: In
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CmdDelegatedGetLocal(
|
||||||
|
internal val delegateSlot: Int,
|
||||||
|
internal val nameId: Int,
|
||||||
|
internal val dst: Int,
|
||||||
|
) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
|
?: error("DELEGATED_GET_LOCAL expects StringVal at $nameId")
|
||||||
|
val delegate = frame.slotToObj(delegateSlot)
|
||||||
|
val scope = frame.ensureScope()
|
||||||
|
val rec = ObjRecord(ObjNull, isMutable = false, type = ObjRecord.Type.Delegated)
|
||||||
|
rec.delegate = delegate
|
||||||
|
val resolved = ObjVoid.resolveRecord(scope, rec, nameConst.value, null)
|
||||||
|
frame.storeObjResult(dst, resolved.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CmdDelegatedSetLocal(
|
||||||
|
internal val delegateSlot: Int,
|
||||||
|
internal val nameId: Int,
|
||||||
|
internal val valueSlot: Int,
|
||||||
|
) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
|
?: error("DELEGATED_SET_LOCAL expects StringVal at $nameId")
|
||||||
|
val delegate = frame.slotToObj(delegateSlot)
|
||||||
|
val scope = frame.ensureScope()
|
||||||
|
val value = frame.slotToObj(valueSlot)
|
||||||
|
delegate.invokeInstanceMethod(scope, "setValue", Arguments(ObjNull, ObjString(nameConst.value), value))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CmdBindDelegateLocal(
|
||||||
|
internal val delegateSlot: Int,
|
||||||
|
internal val nameId: Int,
|
||||||
|
internal val accessId: Int,
|
||||||
|
internal val dst: Int,
|
||||||
|
) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
|
?: error("BIND_DELEGATE_LOCAL expects StringVal at $nameId")
|
||||||
|
val accessConst = frame.fn.constants.getOrNull(accessId) as? BytecodeConst.StringVal
|
||||||
|
?: error("BIND_DELEGATE_LOCAL expects StringVal at $accessId")
|
||||||
|
val delegate = frame.slotToObj(delegateSlot)
|
||||||
|
val scope = frame.ensureScope()
|
||||||
|
val bound = try {
|
||||||
|
delegate.invokeInstanceMethod(
|
||||||
|
scope,
|
||||||
|
"bind",
|
||||||
|
Arguments(ObjString(nameConst.value), ObjString(accessConst.value), ObjNull)
|
||||||
|
)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
delegate
|
||||||
|
}
|
||||||
|
frame.storeObjResult(dst, bound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CmdIntToReal(internal val src: Int, internal val dst: Int) : Cmd() {
|
class CmdIntToReal(internal val src: Int, internal val dst: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
frame.setReal(dst, frame.getReal(src))
|
frame.setReal(dst, frame.getReal(src))
|
||||||
@ -2274,7 +2335,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
val local = slot - fn.scopeSlotCount
|
val local = slot - fn.scopeSlotCount
|
||||||
val localName = fn.localSlotNames.getOrNull(local)
|
val localName = fn.localSlotNames.getOrNull(local)
|
||||||
if (localName != null) {
|
if (localName != null && fn.localSlotDelegated.getOrNull(local) != true) {
|
||||||
val rec = scope.getLocalRecordDirect(localName) ?: scope.localBindings[localName]
|
val rec = scope.getLocalRecordDirect(localName) ?: scope.localBindings[localName]
|
||||||
if (rec != null && (rec.type == ObjRecord.Type.Delegated || rec.type == ObjRecord.Type.Property || rec.value is ObjProperty)) {
|
if (rec != null && (rec.type == ObjRecord.Type.Delegated || rec.type == ObjRecord.Type.Property || rec.value is ObjProperty)) {
|
||||||
return scope.resolve(rec, localName)
|
return scope.resolve(rec, localName)
|
||||||
@ -2329,12 +2390,27 @@ class CmdFrame(
|
|||||||
val name = names[i] ?: continue
|
val name = names[i] ?: continue
|
||||||
if (scopeSlotNames.contains(name)) continue
|
if (scopeSlotNames.contains(name)) continue
|
||||||
val target = resolveLocalScope(i) ?: continue
|
val target = resolveLocalScope(i) ?: continue
|
||||||
|
val isDelegated = fn.localSlotDelegated.getOrNull(i) == true
|
||||||
val value = if (useRefs) FrameSlotRef(frame, i) else localSlotToObj(i)
|
val value = if (useRefs) FrameSlotRef(frame, i) else localSlotToObj(i)
|
||||||
val rec = target.getLocalRecordDirect(name)
|
val rec = target.getLocalRecordDirect(name)
|
||||||
if (rec == null) {
|
if (rec == null) {
|
||||||
val isMutable = fn.localSlotMutables.getOrElse(i) { true }
|
val isMutable = fn.localSlotMutables.getOrElse(i) { true }
|
||||||
target.addItem(name, isMutable, value)
|
if (isDelegated) {
|
||||||
|
val delegatedRec = target.addItem(
|
||||||
|
name,
|
||||||
|
isMutable,
|
||||||
|
ObjNull,
|
||||||
|
recordType = ObjRecord.Type.Delegated
|
||||||
|
)
|
||||||
|
delegatedRec.delegate = localSlotToObj(i)
|
||||||
|
} else {
|
||||||
|
target.addItem(name, isMutable, value)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (isDelegated && rec.type == ObjRecord.Type.Delegated) {
|
||||||
|
rec.delegate = localSlotToObj(i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
val existing = rec.value
|
val existing = rec.value
|
||||||
if (existing is FrameSlotRef && !useRefs) continue
|
if (existing is FrameSlotRef && !useRefs) continue
|
||||||
rec.value = value
|
rec.value = value
|
||||||
@ -2349,6 +2425,11 @@ class CmdFrame(
|
|||||||
val name = names[i] ?: continue
|
val name = names[i] ?: continue
|
||||||
val target = resolveLocalScope(i) ?: continue
|
val target = resolveLocalScope(i) ?: continue
|
||||||
val rec = target.getLocalRecordDirect(name) ?: continue
|
val rec = target.getLocalRecordDirect(name) ?: continue
|
||||||
|
if (fn.localSlotDelegated.getOrNull(i) == true && rec.type == ObjRecord.Type.Delegated) {
|
||||||
|
val delegate = rec.delegate ?: ObjNull
|
||||||
|
frame.setObj(i, delegate)
|
||||||
|
continue
|
||||||
|
}
|
||||||
val value = rec.value
|
val value = rec.value
|
||||||
if (value is FrameSlotRef) {
|
if (value is FrameSlotRef) {
|
||||||
val resolved = value.read()
|
val resolved = value.read()
|
||||||
|
|||||||
@ -162,6 +162,9 @@ enum class Opcode(val code: Int) {
|
|||||||
ITER_POP(0xC0),
|
ITER_POP(0xC0),
|
||||||
ITER_CANCEL(0xC1),
|
ITER_CANCEL(0xC1),
|
||||||
ASSIGN_SCOPE_SLOT(0xC2),
|
ASSIGN_SCOPE_SLOT(0xC2),
|
||||||
|
DELEGATED_GET_LOCAL(0xC3),
|
||||||
|
DELEGATED_SET_LOCAL(0xC4),
|
||||||
|
BIND_DELEGATE_LOCAL(0xC5),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user