Compare commits
No commits in common. "58581d6bf004210183a6c0e955cdbcc1e3dadca2" and "5fd322a43e6d7b688c32b8bfe970a24fe50b6d2d" have entirely different histories.
58581d6bf0
...
5fd322a43e
@ -27,11 +27,11 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Replace `MapLiteralEntry.Spread` bytecode exception with runtime `putAll`/merge logic.
|
- [x] Replace `MapLiteralEntry.Spread` bytecode exception with runtime `putAll`/merge logic.
|
||||||
- [x] Step 7: Class-scope member refs in bytecode.
|
- [x] Step 7: Class-scope member refs in bytecode.
|
||||||
- [x] Support `ClassScopeMemberRef` without scope-map fallback.
|
- [x] Support `ClassScopeMemberRef` without scope-map fallback.
|
||||||
- [x] Step 8: ObjDynamic member access in bytecode.
|
- [ ] Step 8: ObjDynamic member access in bytecode.
|
||||||
- [x] Allow dynamic receiver field/method lookup without falling back to interpreter.
|
- [ ] Allow dynamic receiver field/method lookup without falling back to interpreter.
|
||||||
- [x] Step 9: Module-level bytecode execution.
|
- [ ] Step 9: Module-level bytecode execution.
|
||||||
- [x] Compile `Script` bodies to bytecode instead of interpreting at module scope.
|
- [ ] Compile `Script` bodies to bytecode instead of interpreting at module scope.
|
||||||
- [x] Keep import/module slot seeding in frame-only flow.
|
- [ ] Keep import/module slot seeding in frame-only flow.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@ -1526,10 +1526,11 @@ class Compiler(
|
|||||||
resolutionScriptDepth == 1 &&
|
resolutionScriptDepth == 1 &&
|
||||||
statements.none { containsUnsupportedForBytecode(it) } &&
|
statements.none { containsUnsupportedForBytecode(it) } &&
|
||||||
statements.none { containsDelegatedRefs(it) }
|
statements.none { containsDelegatedRefs(it) }
|
||||||
val (finalStatements, moduleBytecode) = if (wrapScriptBytecode) {
|
val finalStatements = if (wrapScriptBytecode) {
|
||||||
val unwrapped = statements.map { unwrapBytecodeDeep(it) }
|
val unwrapped = statements.map { unwrapBytecodeDeep(it) }
|
||||||
val block = InlineBlockStatement(unwrapped, start)
|
val block = InlineBlockStatement(unwrapped, start)
|
||||||
val bytecodeStmt = BytecodeStatement.wrap(
|
listOf(
|
||||||
|
BytecodeStatement.wrap(
|
||||||
block,
|
block,
|
||||||
"<script>",
|
"<script>",
|
||||||
allowLocalSlots = true,
|
allowLocalSlots = true,
|
||||||
@ -1537,13 +1538,13 @@ class Compiler(
|
|||||||
moduleScopeId = moduleSlotPlan()?.id,
|
moduleScopeId = moduleSlotPlan()?.id,
|
||||||
slotTypeByScopeId = slotTypeByScopeId,
|
slotTypeByScopeId = slotTypeByScopeId,
|
||||||
knownNameObjClass = knownClassMapForBytecode()
|
knownNameObjClass = knownClassMapForBytecode()
|
||||||
) as BytecodeStatement
|
)
|
||||||
unwrapped to bytecodeStmt.bytecodeFunction()
|
)
|
||||||
} else {
|
} else {
|
||||||
statements to null
|
statements
|
||||||
}
|
}
|
||||||
val moduleRefs = importedModules.map { ImportBindingSource.Module(it.scope.packageName, it.pos) }
|
val moduleRefs = importedModules.map { ImportBindingSource.Module(it.scope.packageName, it.pos) }
|
||||||
Script(start, finalStatements, modulePlan, importBindings.toMap(), moduleRefs, moduleBytecode)
|
Script(start, finalStatements, modulePlan, importBindings.toMap(), moduleRefs)
|
||||||
}.also {
|
}.also {
|
||||||
// Best-effort script end notification (use current position)
|
// Best-effort script end notification (use current position)
|
||||||
miniSink?.onScriptEnd(
|
miniSink?.onScriptEnd(
|
||||||
@ -1943,6 +1944,7 @@ class Compiler(
|
|||||||
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
|
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
|
||||||
is FieldRef -> {
|
is FieldRef -> {
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.target) ?: return true
|
val receiverClass = resolveReceiverClassForMember(ref.target) ?: return true
|
||||||
|
if (receiverClass == ObjDynamic.type) return true
|
||||||
val hasMember = receiverClass.instanceFieldIdMap()[ref.name] != null ||
|
val hasMember = receiverClass.instanceFieldIdMap()[ref.name] != null ||
|
||||||
receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
||||||
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
||||||
@ -1973,6 +1975,7 @@ class Compiler(
|
|||||||
is MethodCallRef -> {
|
is MethodCallRef -> {
|
||||||
if (ref.name == "delay") return true
|
if (ref.name == "delay") return true
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.receiver) ?: return true
|
val receiverClass = resolveReceiverClassForMember(ref.receiver) ?: return true
|
||||||
|
if (receiverClass == ObjDynamic.type) return true
|
||||||
val hasMember = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
val hasMember = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
||||||
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
||||||
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||||
|
|||||||
@ -20,8 +20,6 @@ package net.sergeych.lyng
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
import net.sergeych.lyng.Script.Companion.defaultImportManager
|
import net.sergeych.lyng.Script.Companion.defaultImportManager
|
||||||
import net.sergeych.lyng.bytecode.CmdFunction
|
|
||||||
import net.sergeych.lyng.bytecode.CmdVm
|
|
||||||
import net.sergeych.lyng.miniast.*
|
import net.sergeych.lyng.miniast.*
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportManager
|
import net.sergeych.lyng.pacman.ImportManager
|
||||||
@ -37,12 +35,10 @@ class Script(
|
|||||||
private val moduleSlotPlan: Map<String, Int> = emptyMap(),
|
private val moduleSlotPlan: Map<String, Int> = emptyMap(),
|
||||||
private val importBindings: Map<String, ImportBinding> = emptyMap(),
|
private val importBindings: Map<String, ImportBinding> = emptyMap(),
|
||||||
private val importedModules: List<ImportBindingSource.Module> = emptyList(),
|
private val importedModules: List<ImportBindingSource.Module> = emptyList(),
|
||||||
private val moduleBytecode: CmdFunction? = null,
|
|
||||||
// private val catchReturn: Boolean = false,
|
// private val catchReturn: Boolean = false,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
scope.pos = pos
|
|
||||||
val isModuleScope = scope is ModuleScope
|
val isModuleScope = scope is ModuleScope
|
||||||
val shouldSeedModule = isModuleScope || scope.thisObj === ObjVoid
|
val shouldSeedModule = isModuleScope || scope.thisObj === ObjVoid
|
||||||
val moduleTarget = scope
|
val moduleTarget = scope
|
||||||
@ -83,9 +79,6 @@ class Script(
|
|||||||
if (shouldSeedModule) {
|
if (shouldSeedModule) {
|
||||||
seedModuleSlots(moduleTarget)
|
seedModuleSlots(moduleTarget)
|
||||||
}
|
}
|
||||||
moduleBytecode?.let { fn ->
|
|
||||||
return CmdVm().execute(fn, scope, scope.args.list)
|
|
||||||
}
|
|
||||||
var lastResult: Obj = ObjVoid
|
var lastResult: Obj = ObjVoid
|
||||||
for (s in statements) {
|
for (s in statements) {
|
||||||
lastResult = s.execute(scope)
|
lastResult = s.execute(scope)
|
||||||
|
|||||||
@ -1670,25 +1670,6 @@ class BytecodeCompiler(
|
|||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
)
|
)
|
||||||
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
|
||||||
if (!target.isOptional) {
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, value.slot)
|
|
||||||
} else {
|
|
||||||
val nullSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
|
||||||
val cmpSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, nullSlot, cmpSlot)
|
|
||||||
val endLabel = builder.label()
|
|
||||||
builder.emit(
|
|
||||||
Opcode.JMP_IF_TRUE,
|
|
||||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(endLabel))
|
|
||||||
)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, value.slot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[target.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[target.name]
|
||||||
val methodId = if (fieldId == null) {
|
val methodId = if (fieldId == null) {
|
||||||
receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name]
|
receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name]
|
||||||
@ -1887,24 +1868,6 @@ class BytecodeCompiler(
|
|||||||
} ?: return compileEvalRef(ref)
|
} ?: return compileEvalRef(ref)
|
||||||
val fieldTarget = ref.target as? FieldRef
|
val fieldTarget = ref.target as? FieldRef
|
||||||
if (fieldTarget != null) {
|
if (fieldTarget != null) {
|
||||||
if (fieldTarget.isOptional) return compileEvalRef(ref)
|
|
||||||
val receiverClass = resolveReceiverClass(fieldTarget.target)
|
|
||||||
?: throw BytecodeCompileException(
|
|
||||||
"Member assignment requires compile-time receiver type: ${fieldTarget.name}",
|
|
||||||
Pos.builtIn
|
|
||||||
)
|
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
|
||||||
val current = allocSlot()
|
|
||||||
val result = allocSlot()
|
|
||||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
|
||||||
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, current)
|
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
|
||||||
updateSlotType(result, SlotType.OBJ)
|
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
throw BytecodeCompileException(
|
throw BytecodeCompileException(
|
||||||
"Member assignment requires compile-time receiver type: ${fieldTarget.name}",
|
"Member assignment requires compile-time receiver type: ${fieldTarget.name}",
|
||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
@ -2045,29 +2008,6 @@ class BytecodeCompiler(
|
|||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
)
|
)
|
||||||
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
|
||||||
if (!target.isOptional) {
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, newValue.slot)
|
|
||||||
} else {
|
|
||||||
val recvNull = allocSlot()
|
|
||||||
builder.emit(Opcode.CONST_NULL, recvNull)
|
|
||||||
val recvCmp = allocSlot()
|
|
||||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, recvNull, recvCmp)
|
|
||||||
val skipLabel = builder.label()
|
|
||||||
builder.emit(
|
|
||||||
Opcode.JMP_IF_TRUE,
|
|
||||||
listOf(CmdBuilder.Operand.IntVal(recvCmp), CmdBuilder.Operand.LabelRef(skipLabel))
|
|
||||||
)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, newValue.slot)
|
|
||||||
builder.mark(skipLabel)
|
|
||||||
}
|
|
||||||
val newObj = ensureObjSlot(newValue)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, newObj.slot, resultSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
updateSlotType(resultSlot, SlotType.OBJ)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[target.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[target.name]
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name]
|
||||||
if (fieldId != null || methodId != null) {
|
if (fieldId != null || methodId != null) {
|
||||||
@ -2158,32 +2098,6 @@ class BytecodeCompiler(
|
|||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val receiver = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
|
||||||
val dst = allocSlot()
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
|
||||||
if (!ref.isOptional) {
|
|
||||||
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, dst)
|
|
||||||
} else {
|
|
||||||
val nullSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
|
||||||
val cmpSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, nullSlot, cmpSlot)
|
|
||||||
val nullLabel = builder.label()
|
|
||||||
val endLabel = builder.label()
|
|
||||||
builder.emit(
|
|
||||||
Opcode.JMP_IF_TRUE,
|
|
||||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
|
||||||
)
|
|
||||||
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, dst)
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, dst)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
}
|
|
||||||
updateSlotType(dst, SlotType.OBJ)
|
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[ref.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[ref.name]
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
||||||
val encodedFieldId = encodeMemberId(receiverClass, fieldId)
|
val encodedFieldId = encodeMemberId(receiverClass, fieldId)
|
||||||
@ -2699,29 +2613,6 @@ class BytecodeCompiler(
|
|||||||
"Member access requires compile-time receiver type: ${fieldTarget.name}",
|
"Member access requires compile-time receiver type: ${fieldTarget.name}",
|
||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
)
|
)
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
|
||||||
val current = allocSlot()
|
|
||||||
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, current)
|
|
||||||
updateSlotType(current, SlotType.OBJ)
|
|
||||||
val oneSlot = allocSlot()
|
|
||||||
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
|
|
||||||
builder.emit(Opcode.CONST_OBJ, oneId, oneSlot)
|
|
||||||
updateSlotType(oneSlot, SlotType.OBJ)
|
|
||||||
val result = allocSlot()
|
|
||||||
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
|
|
||||||
if (wantResult && ref.isPost) {
|
|
||||||
val old = allocSlot()
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, current, old)
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
|
||||||
return CompiledValue(old, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[fieldTarget.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[fieldTarget.name]
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[fieldTarget.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[fieldTarget.name]
|
||||||
if (fieldId == null && methodId == null) return null
|
if (fieldId == null && methodId == null) return null
|
||||||
@ -3035,33 +2926,6 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
val receiver = compileRefWithFallback(ref.receiver, null, refPosOrCurrent(ref.receiver)) ?: return null
|
val receiver = compileRefWithFallback(ref.receiver, null, refPosOrCurrent(ref.receiver)) ?: return null
|
||||||
val dst = allocSlot()
|
val dst = allocSlot()
|
||||||
if (receiverClass == ObjDynamic.type) {
|
|
||||||
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
|
||||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
|
||||||
if (!ref.isOptional) {
|
|
||||||
setPos(callPos)
|
|
||||||
builder.emit(Opcode.CALL_DYNAMIC_MEMBER, receiver.slot, nameId, args.base, encodedCount, dst)
|
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val nullSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
|
||||||
val cmpSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, nullSlot, cmpSlot)
|
|
||||||
val nullLabel = builder.label()
|
|
||||||
val endLabel = builder.label()
|
|
||||||
builder.emit(
|
|
||||||
Opcode.JMP_IF_TRUE,
|
|
||||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
|
||||||
)
|
|
||||||
setPos(callPos)
|
|
||||||
builder.emit(Opcode.CALL_DYNAMIC_MEMBER, receiver.slot, nameId, args.base, encodedCount, dst)
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, dst)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
||||||
if (methodId != null) {
|
if (methodId != null) {
|
||||||
val encodedMethodId = encodeMemberId(receiverClass, methodId) ?: methodId
|
val encodedMethodId = encodeMemberId(receiverClass, methodId) ?: methodId
|
||||||
|
|||||||
@ -181,8 +181,6 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
||||||
Opcode.CALL_SLOT ->
|
Opcode.CALL_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
||||||
Opcode.CALL_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
|
||||||
Opcode.GET_INDEX ->
|
Opcode.GET_INDEX ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.SET_INDEX ->
|
Opcode.SET_INDEX ->
|
||||||
@ -199,10 +197,6 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.SET_CLASS_SCOPE ->
|
Opcode.SET_CLASS_SCOPE ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.GET_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
|
||||||
Opcode.SET_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
|
||||||
Opcode.ITER_PUSH ->
|
Opcode.ITER_PUSH ->
|
||||||
listOf(OperandKind.SLOT)
|
listOf(OperandKind.SLOT)
|
||||||
Opcode.ITER_POP, Opcode.ITER_CANCEL ->
|
Opcode.ITER_POP, Opcode.ITER_CANCEL ->
|
||||||
@ -400,7 +394,6 @@ class CmdBuilder {
|
|||||||
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.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.GET_INDEX -> CmdGetIndex(operands[0], operands[1], operands[2])
|
Opcode.GET_INDEX -> CmdGetIndex(operands[0], operands[1], operands[2])
|
||||||
Opcode.SET_INDEX -> CmdSetIndex(operands[0], operands[1], operands[2])
|
Opcode.SET_INDEX -> CmdSetIndex(operands[0], operands[1], operands[2])
|
||||||
Opcode.LIST_LITERAL -> CmdListLiteral(operands[0], operands[1], operands[2], operands[3])
|
Opcode.LIST_LITERAL -> CmdListLiteral(operands[0], operands[1], operands[2], operands[3])
|
||||||
@ -408,8 +401,6 @@ class CmdBuilder {
|
|||||||
Opcode.SET_MEMBER_SLOT -> CmdSetMemberSlot(operands[0], operands[1], operands[2], operands[3])
|
Opcode.SET_MEMBER_SLOT -> CmdSetMemberSlot(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.GET_CLASS_SCOPE -> CmdGetClassScope(operands[0], operands[1], operands[2])
|
Opcode.GET_CLASS_SCOPE -> CmdGetClassScope(operands[0], operands[1], operands[2])
|
||||||
Opcode.SET_CLASS_SCOPE -> CmdSetClassScope(operands[0], operands[1], operands[2])
|
Opcode.SET_CLASS_SCOPE -> CmdSetClassScope(operands[0], operands[1], operands[2])
|
||||||
Opcode.GET_DYNAMIC_MEMBER -> CmdGetDynamicMember(operands[0], operands[1], operands[2])
|
|
||||||
Opcode.SET_DYNAMIC_MEMBER -> CmdSetDynamicMember(operands[0], operands[1], operands[2])
|
|
||||||
Opcode.ITER_PUSH -> CmdIterPush(operands[0])
|
Opcode.ITER_PUSH -> CmdIterPush(operands[0])
|
||||||
Opcode.ITER_POP -> CmdIterPop()
|
Opcode.ITER_POP -> CmdIterPop()
|
||||||
Opcode.ITER_CANCEL -> CmdIterCancel()
|
Opcode.ITER_CANCEL -> CmdIterCancel()
|
||||||
|
|||||||
@ -195,7 +195,6 @@ object CmdDisassembler {
|
|||||||
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 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 CmdGetIndex -> Opcode.GET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.dst)
|
is CmdGetIndex -> Opcode.GET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.dst)
|
||||||
is CmdSetIndex -> Opcode.SET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.valueSlot)
|
is CmdSetIndex -> Opcode.SET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.valueSlot)
|
||||||
is CmdListLiteral -> Opcode.LIST_LITERAL to intArrayOf(cmd.planId, cmd.baseSlot, cmd.count, cmd.dst)
|
is CmdListLiteral -> Opcode.LIST_LITERAL to intArrayOf(cmd.planId, cmd.baseSlot, cmd.count, cmd.dst)
|
||||||
@ -203,8 +202,6 @@ object CmdDisassembler {
|
|||||||
is CmdSetMemberSlot -> Opcode.SET_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.fieldId, cmd.methodId, cmd.valueSlot)
|
is CmdSetMemberSlot -> Opcode.SET_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.fieldId, cmd.methodId, cmd.valueSlot)
|
||||||
is CmdGetClassScope -> Opcode.GET_CLASS_SCOPE to intArrayOf(cmd.classSlot, cmd.nameId, cmd.dst)
|
is CmdGetClassScope -> Opcode.GET_CLASS_SCOPE to intArrayOf(cmd.classSlot, cmd.nameId, cmd.dst)
|
||||||
is CmdSetClassScope -> Opcode.SET_CLASS_SCOPE to intArrayOf(cmd.classSlot, cmd.nameId, cmd.valueSlot)
|
is CmdSetClassScope -> Opcode.SET_CLASS_SCOPE to intArrayOf(cmd.classSlot, cmd.nameId, cmd.valueSlot)
|
||||||
is CmdGetDynamicMember -> Opcode.GET_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.dst)
|
|
||||||
is CmdSetDynamicMember -> Opcode.SET_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.valueSlot)
|
|
||||||
is CmdIterPush -> Opcode.ITER_PUSH to intArrayOf(cmd.iterSlot)
|
is CmdIterPush -> Opcode.ITER_PUSH to intArrayOf(cmd.iterSlot)
|
||||||
is CmdIterPop -> Opcode.ITER_POP to intArrayOf()
|
is CmdIterPop -> Opcode.ITER_POP to intArrayOf()
|
||||||
is CmdIterCancel -> Opcode.ITER_CANCEL to intArrayOf()
|
is CmdIterCancel -> Opcode.ITER_CANCEL to intArrayOf()
|
||||||
@ -288,8 +285,6 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
||||||
Opcode.CALL_MEMBER_SLOT ->
|
Opcode.CALL_MEMBER_SLOT ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
||||||
Opcode.CALL_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT)
|
|
||||||
Opcode.GET_INDEX ->
|
Opcode.GET_INDEX ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||||
Opcode.SET_INDEX ->
|
Opcode.SET_INDEX ->
|
||||||
@ -304,10 +299,6 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.SET_CLASS_SCOPE ->
|
Opcode.SET_CLASS_SCOPE ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.GET_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
|
||||||
Opcode.SET_DYNAMIC_MEMBER ->
|
|
||||||
listOf(OperandKind.SLOT, OperandKind.CONST, OperandKind.SLOT)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1404,21 +1404,6 @@ private fun decodeMemberId(id: Int): Pair<Int, Boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun resolveDynamicFieldValue(scope: Scope, receiver: Obj, name: String, rec: ObjRecord): Obj {
|
|
||||||
if (rec.type == ObjRecord.Type.Delegated || rec.value is ObjProperty || rec.type == ObjRecord.Type.Property) {
|
|
||||||
val recv = rec.receiver ?: receiver
|
|
||||||
return recv.resolveRecord(scope, rec, name, rec.declaringClass).value
|
|
||||||
}
|
|
||||||
if (rec.receiver != null && rec.declaringClass != null) {
|
|
||||||
return rec.receiver!!.resolveRecord(scope, rec, name, rec.declaringClass).value
|
|
||||||
}
|
|
||||||
if (rec.type == ObjRecord.Type.Fun && !rec.isAbstract) {
|
|
||||||
val recv = rec.receiver ?: receiver
|
|
||||||
return rec.value.invoke(scope, recv, Arguments.EMPTY, rec.declaringClass)
|
|
||||||
}
|
|
||||||
return rec.value
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdGetMemberSlot(
|
class CmdGetMemberSlot(
|
||||||
internal val recvSlot: Int,
|
internal val recvSlot: Int,
|
||||||
internal val fieldId: Int,
|
internal val fieldId: Int,
|
||||||
@ -1542,75 +1527,6 @@ class CmdSetClassScope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CmdGetDynamicMember(
|
|
||||||
internal val recvSlot: Int,
|
|
||||||
internal val nameId: Int,
|
|
||||||
internal val dst: Int,
|
|
||||||
) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
|
||||||
?: error("GET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
|
||||||
val scope = frame.ensureScope()
|
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
|
||||||
val rec = receiver.readField(scope, nameConst.value)
|
|
||||||
val value = resolveDynamicFieldValue(scope, receiver, nameConst.value, rec)
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdSetDynamicMember(
|
|
||||||
internal val recvSlot: Int,
|
|
||||||
internal val nameId: Int,
|
|
||||||
internal val valueSlot: Int,
|
|
||||||
) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
|
||||||
?: error("SET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
|
||||||
val scope = frame.ensureScope()
|
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
|
||||||
receiver.writeField(scope, nameConst.value, frame.slotToObj(valueSlot))
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdCallDynamicMember(
|
|
||||||
internal val recvSlot: Int,
|
|
||||||
internal val nameId: Int,
|
|
||||||
internal val argBase: Int,
|
|
||||||
internal val argCount: Int,
|
|
||||||
internal val dst: Int,
|
|
||||||
) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
|
||||||
?: error("CALL_DYNAMIC_MEMBER expects StringVal at $nameId")
|
|
||||||
val scope = frame.ensureScope()
|
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
|
||||||
val callArgs = frame.buildArguments(argBase, argCount)
|
|
||||||
val result = receiver.invokeInstanceMethod(scope, nameConst.value, callArgs)
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdCallMemberSlot(
|
class CmdCallMemberSlot(
|
||||||
internal val recvSlot: Int,
|
internal val recvSlot: Int,
|
||||||
internal val methodId: Int,
|
internal val methodId: Int,
|
||||||
|
|||||||
@ -142,9 +142,6 @@ enum class Opcode(val code: Int) {
|
|||||||
SET_MEMBER_SLOT(0xA9),
|
SET_MEMBER_SLOT(0xA9),
|
||||||
GET_CLASS_SCOPE(0xAA),
|
GET_CLASS_SCOPE(0xAA),
|
||||||
SET_CLASS_SCOPE(0xAB),
|
SET_CLASS_SCOPE(0xAB),
|
||||||
GET_DYNAMIC_MEMBER(0xAC),
|
|
||||||
SET_DYNAMIC_MEMBER(0xAD),
|
|
||||||
CALL_DYNAMIC_MEMBER(0xAE),
|
|
||||||
|
|
||||||
RESOLVE_SCOPE_SLOT(0xB1),
|
RESOLVE_SCOPE_SLOT(0xB1),
|
||||||
LOAD_OBJ_ADDR(0xB2),
|
LOAD_OBJ_ADDR(0xB2),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user