Compare commits
No commits in common. "473a5dd6ed94ec13763d9702c11531ebbfa44ddb" and "58581d6bf004210183a6c0e955cdbcc1e3dadca2" have entirely different histories.
473a5dd6ed
...
58581d6bf0
@ -32,17 +32,6 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Step 9: Module-level bytecode execution.
|
- [x] Step 9: Module-level bytecode execution.
|
||||||
- [x] Compile `Script` bodies to bytecode instead of interpreting at module scope.
|
- [x] Compile `Script` bodies to bytecode instead of interpreting at module scope.
|
||||||
- [x] Keep import/module slot seeding in frame-only flow.
|
- [x] Keep import/module slot seeding in frame-only flow.
|
||||||
- [x] Step 10: Bytecode for declaration statements in module scripts.
|
|
||||||
- [x] Support `ClassDeclStatement`, `FunctionDeclStatement`, `EnumDeclStatement` in bytecode compilation.
|
|
||||||
- [x] Keep a mixed execution path for declarations (module bytecode calls statement bodies via `CALL_SLOT`).
|
|
||||||
- [x] Ensure module object member refs compile as instance access (not class-scope).
|
|
||||||
- [x] Step 11: Destructuring assignment bytecode.
|
|
||||||
- [x] Handle `[a, b] = expr` (AssignRef target `ListLiteralRef`) without interpreter fallback.
|
|
||||||
- [x] Step 12: Optional member assign-ops and inc/dec in bytecode.
|
|
||||||
- [x] Support `a?.b += 1` and `a?.b++` for `FieldRef` targets.
|
|
||||||
- [x] Fix post-inc return value for object slots stored in scope frames.
|
|
||||||
- [x] Handle optional receivers for member assign-ops and inc/dec without evaluating operands on null.
|
|
||||||
- [x] Support class-scope and index optional inc/dec paths in bytecode.
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@ -28,9 +28,4 @@ class ClassDeclStatement(
|
|||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return delegate.execute(scope)
|
return delegate.execute(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
|
||||||
val target = scope.parent ?: scope
|
|
||||||
return delegate.execute(target)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -165,7 +165,6 @@ class Compiler(
|
|||||||
private val classScopeCallableMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
private val classScopeCallableMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
||||||
private val encodedPayloadTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
private val encodedPayloadTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
||||||
private val encodedPayloadTypeByName: MutableMap<String, ObjClass> = mutableMapOf()
|
private val encodedPayloadTypeByName: MutableMap<String, ObjClass> = mutableMapOf()
|
||||||
private val objectDeclNames: MutableSet<String> = mutableSetOf()
|
|
||||||
|
|
||||||
private fun seedSlotPlanFromScope(scope: Scope, includeParents: Boolean = false) {
|
private fun seedSlotPlanFromScope(scope: Scope, includeParents: Boolean = false) {
|
||||||
val plan = moduleSlotPlan() ?: return
|
val plan = moduleSlotPlan() ?: return
|
||||||
@ -1537,12 +1536,7 @@ class Compiler(
|
|||||||
allowedScopeNames = modulePlan.keys,
|
allowedScopeNames = modulePlan.keys,
|
||||||
moduleScopeId = moduleSlotPlan()?.id,
|
moduleScopeId = moduleSlotPlan()?.id,
|
||||||
slotTypeByScopeId = slotTypeByScopeId,
|
slotTypeByScopeId = slotTypeByScopeId,
|
||||||
knownNameObjClass = knownClassMapForBytecode(),
|
knownNameObjClass = knownClassMapForBytecode()
|
||||||
knownObjectNames = objectDeclNames,
|
|
||||||
classFieldTypesByName = classFieldTypesByName,
|
|
||||||
enumEntriesByName = enumEntriesByName,
|
|
||||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
|
||||||
callableReturnTypeByName = callableReturnTypeByName
|
|
||||||
) as BytecodeStatement
|
) as BytecodeStatement
|
||||||
unwrapped to bytecodeStmt.bytecodeFunction()
|
unwrapped to bytecodeStmt.bytecodeFunction()
|
||||||
} else {
|
} else {
|
||||||
@ -1836,12 +1830,7 @@ class Compiler(
|
|||||||
allowedScopeNames = allowedScopeNames,
|
allowedScopeNames = allowedScopeNames,
|
||||||
moduleScopeId = moduleSlotPlan()?.id,
|
moduleScopeId = moduleSlotPlan()?.id,
|
||||||
slotTypeByScopeId = slotTypeByScopeId,
|
slotTypeByScopeId = slotTypeByScopeId,
|
||||||
knownNameObjClass = knownClassMapForBytecode(),
|
knownNameObjClass = knownClassMapForBytecode()
|
||||||
knownObjectNames = objectDeclNames,
|
|
||||||
classFieldTypesByName = classFieldTypesByName,
|
|
||||||
enumEntriesByName = enumEntriesByName,
|
|
||||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
|
||||||
callableReturnTypeByName = callableReturnTypeByName
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1872,12 +1861,7 @@ class Compiler(
|
|||||||
allowedScopeNames = allowedScopeNames,
|
allowedScopeNames = allowedScopeNames,
|
||||||
moduleScopeId = moduleSlotPlan()?.id,
|
moduleScopeId = moduleSlotPlan()?.id,
|
||||||
slotTypeByScopeId = slotTypeByScopeId,
|
slotTypeByScopeId = slotTypeByScopeId,
|
||||||
knownNameObjClass = knownNames,
|
knownNameObjClass = knownNames
|
||||||
knownObjectNames = objectDeclNames,
|
|
||||||
classFieldTypesByName = classFieldTypesByName,
|
|
||||||
enumEntriesByName = enumEntriesByName,
|
|
||||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
|
||||||
callableReturnTypeByName = callableReturnTypeByName
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1915,9 +1899,6 @@ class Compiler(
|
|||||||
is ReturnStatement -> target.resultExpr?.let { containsUnsupportedForBytecode(it) } ?: false
|
is ReturnStatement -> target.resultExpr?.let { containsUnsupportedForBytecode(it) } ?: false
|
||||||
is ThrowStatement -> containsUnsupportedForBytecode(target.throwExpr)
|
is ThrowStatement -> containsUnsupportedForBytecode(target.throwExpr)
|
||||||
is ExtensionPropertyDeclStatement -> false
|
is ExtensionPropertyDeclStatement -> false
|
||||||
is ClassDeclStatement -> false
|
|
||||||
is FunctionDeclStatement -> false
|
|
||||||
is EnumDeclStatement -> false
|
|
||||||
is TryStatement -> {
|
is TryStatement -> {
|
||||||
containsUnsupportedForBytecode(target.body) ||
|
containsUnsupportedForBytecode(target.body) ||
|
||||||
target.catches.any { containsUnsupportedForBytecode(it.block) } ||
|
target.catches.any { containsUnsupportedForBytecode(it.block) } ||
|
||||||
@ -1949,12 +1930,9 @@ class Compiler(
|
|||||||
is CastRef -> containsUnsupportedRef(ref.castValueRef()) || containsUnsupportedRef(ref.castTypeRef())
|
is CastRef -> containsUnsupportedRef(ref.castValueRef()) || containsUnsupportedRef(ref.castTypeRef())
|
||||||
is net.sergeych.lyng.obj.TypeDeclRef -> false
|
is net.sergeych.lyng.obj.TypeDeclRef -> false
|
||||||
is AssignRef -> {
|
is AssignRef -> {
|
||||||
|
if (ref.target is ListLiteralRef) return true
|
||||||
val target = ref.target as? LocalSlotRef
|
val target = ref.target as? LocalSlotRef
|
||||||
if (target != null) {
|
(target?.isDelegated == true) || containsUnsupportedRef(ref.value)
|
||||||
(target.isDelegated) || containsUnsupportedRef(ref.value)
|
|
||||||
} else {
|
|
||||||
containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is AssignOpRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
is AssignOpRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
is AssignIfNullRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
is AssignIfNullRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||||
@ -1989,9 +1967,11 @@ class Compiler(
|
|||||||
is LocalSlotRef -> target.name
|
is LocalSlotRef -> target.name
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
if (targetName == "delay") return true
|
||||||
containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||||
}
|
}
|
||||||
is MethodCallRef -> {
|
is MethodCallRef -> {
|
||||||
|
if (ref.name == "delay") return true
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.receiver) ?: return true
|
val receiverClass = resolveReceiverClassForMember(ref.receiver) ?: 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
|
||||||
@ -5682,9 +5662,6 @@ class Compiler(
|
|||||||
if (declaredName != null) {
|
if (declaredName != null) {
|
||||||
resolutionSink?.declareSymbol(declaredName, SymbolKind.CLASS, isMutable = false, pos = nameToken!!.pos)
|
resolutionSink?.declareSymbol(declaredName, SymbolKind.CLASS, isMutable = false, pos = nameToken!!.pos)
|
||||||
declareLocalName(declaredName, isMutable = false)
|
declareLocalName(declaredName, isMutable = false)
|
||||||
if (codeContexts.lastOrNull() is CodeContext.Module) {
|
|
||||||
objectDeclNames.add(declaredName)
|
|
||||||
}
|
|
||||||
if (outerClassName != null) {
|
if (outerClassName != null) {
|
||||||
val outerCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
val outerCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
||||||
outerCtx?.classScopeMembers?.add(declaredName)
|
outerCtx?.classScopeMembers?.add(declaredName)
|
||||||
@ -6637,17 +6614,11 @@ class Compiler(
|
|||||||
val declKind = if (parentContext is CodeContext.ClassBody) SymbolKind.MEMBER else SymbolKind.FUNCTION
|
val declKind = if (parentContext is CodeContext.ClassBody) SymbolKind.MEMBER else SymbolKind.FUNCTION
|
||||||
resolutionSink?.declareSymbol(name, declKind, isMutable = false, pos = nameStartPos, isOverride = isOverride)
|
resolutionSink?.declareSymbol(name, declKind, isMutable = false, pos = nameStartPos, isOverride = isOverride)
|
||||||
if (parentContext is CodeContext.ClassBody && extTypeName == null) {
|
if (parentContext is CodeContext.ClassBody && extTypeName == null) {
|
||||||
if (isStatic) {
|
parentContext.declaredMembers.add(name)
|
||||||
parentContext.classScopeMembers.add(name)
|
if (!parentContext.memberMethodIds.containsKey(name)) {
|
||||||
registerClassScopeMember(parentContext.name, name)
|
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
|
||||||
registerClassScopeCallableMember(parentContext.name, name)
|
|
||||||
} else {
|
|
||||||
parentContext.declaredMembers.add(name)
|
|
||||||
if (!parentContext.memberMethodIds.containsKey(name)) {
|
|
||||||
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
|
|
||||||
}
|
|
||||||
memberMethodId = parentContext.memberMethodIds[name]
|
|
||||||
}
|
}
|
||||||
|
memberMethodId = parentContext.memberMethodIds[name]
|
||||||
}
|
}
|
||||||
if (declKind != SymbolKind.MEMBER) {
|
if (declKind != SymbolKind.MEMBER) {
|
||||||
declareLocalName(name, isMutable = false)
|
declareLocalName(name, isMutable = false)
|
||||||
@ -7783,10 +7754,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (declaringClassNameCaptured != null && extTypeName == null) {
|
if (declaringClassNameCaptured != null && extTypeName == null) {
|
||||||
if (isStatic) {
|
if (isDelegate || isProperty) {
|
||||||
classCtx?.classScopeMembers?.add(name)
|
|
||||||
registerClassScopeMember(declaringClassNameCaptured, name)
|
|
||||||
} else if (isDelegate || isProperty) {
|
|
||||||
if (classCtx != null) {
|
if (classCtx != null) {
|
||||||
if (!classCtx.memberMethodIds.containsKey(name)) {
|
if (!classCtx.memberMethodIds.containsKey(name)) {
|
||||||
classCtx.memberMethodIds[name] = classCtx.nextMethodId++
|
classCtx.memberMethodIds[name] = classCtx.nextMethodId++
|
||||||
|
|||||||
@ -27,9 +27,4 @@ class EnumDeclStatement(
|
|||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return delegate.execute(scope)
|
return delegate.execute(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
|
||||||
val target = scope.parent ?: scope
|
|
||||||
return delegate.execute(target)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,9 +27,4 @@ class FunctionDeclStatement(
|
|||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return delegate.execute(scope)
|
return delegate.execute(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
|
||||||
val target = scope.parent ?: scope
|
|
||||||
return delegate.execute(target)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,11 +28,6 @@ class BytecodeCompiler(
|
|||||||
private val moduleScopeId: Int? = null,
|
private val moduleScopeId: Int? = null,
|
||||||
private val slotTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
private val slotTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
||||||
private val knownNameObjClass: Map<String, ObjClass> = emptyMap(),
|
private val knownNameObjClass: Map<String, ObjClass> = emptyMap(),
|
||||||
private val knownObjectNames: Set<String> = emptySet(),
|
|
||||||
private val classFieldTypesByName: Map<String, Map<String, ObjClass>> = emptyMap(),
|
|
||||||
private val enumEntriesByName: Map<String, List<String>> = emptyMap(),
|
|
||||||
private val callableReturnTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
|
||||||
private val callableReturnTypeByName: Map<String, ObjClass> = emptyMap(),
|
|
||||||
) {
|
) {
|
||||||
private var builder = CmdBuilder()
|
private var builder = CmdBuilder()
|
||||||
private var nextSlot = 0
|
private var nextSlot = 0
|
||||||
@ -59,8 +54,7 @@ class BytecodeCompiler(
|
|||||||
private val localRangeRefs = LinkedHashMap<ScopeSlotKey, RangeRef>()
|
private val localRangeRefs = LinkedHashMap<ScopeSlotKey, RangeRef>()
|
||||||
private val slotTypes = mutableMapOf<Int, SlotType>()
|
private val slotTypes = mutableMapOf<Int, SlotType>()
|
||||||
private val slotObjClass = mutableMapOf<Int, ObjClass>()
|
private val slotObjClass = mutableMapOf<Int, ObjClass>()
|
||||||
private val nameObjClass = knownNameObjClass.toMutableMap()
|
private val nameObjClass = mutableMapOf<String, ObjClass>()
|
||||||
private val knownClassNames = knownNameObjClass.keys.toSet()
|
|
||||||
private val slotInitClassByKey = mutableMapOf<ScopeSlotKey, ObjClass>()
|
private val slotInitClassByKey = mutableMapOf<ScopeSlotKey, ObjClass>()
|
||||||
private val intLoopVarNames = LinkedHashSet<String>()
|
private val intLoopVarNames = LinkedHashSet<String>()
|
||||||
private val loopStack = ArrayDeque<LoopContext>()
|
private val loopStack = ArrayDeque<LoopContext>()
|
||||||
@ -154,54 +148,6 @@ class BytecodeCompiler(
|
|||||||
localSlotMutables
|
localSlotMutables
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> {
|
|
||||||
val value = emitStatementCall(stmt)
|
|
||||||
builder.emit(Opcode.RET, value.slot)
|
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
|
||||||
builder.build(
|
|
||||||
name,
|
|
||||||
localCount,
|
|
||||||
addrCount = nextAddrSlot,
|
|
||||||
returnLabels = returnLabels,
|
|
||||||
scopeSlotIndices,
|
|
||||||
scopeSlotNames,
|
|
||||||
scopeSlotIsModule,
|
|
||||||
localSlotNames,
|
|
||||||
localSlotMutables
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> {
|
|
||||||
val value = emitStatementCall(stmt)
|
|
||||||
builder.emit(Opcode.RET, value.slot)
|
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
|
||||||
builder.build(
|
|
||||||
name,
|
|
||||||
localCount,
|
|
||||||
addrCount = nextAddrSlot,
|
|
||||||
returnLabels = returnLabels,
|
|
||||||
scopeSlotIndices,
|
|
||||||
scopeSlotNames,
|
|
||||||
scopeSlotIsModule,
|
|
||||||
localSlotNames,
|
|
||||||
localSlotMutables
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> {
|
|
||||||
val value = emitStatementCall(stmt)
|
|
||||||
builder.emit(Opcode.RET, value.slot)
|
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
|
||||||
builder.build(
|
|
||||||
name,
|
|
||||||
localCount,
|
|
||||||
addrCount = nextAddrSlot,
|
|
||||||
returnLabels = returnLabels,
|
|
||||||
scopeSlotIndices,
|
|
||||||
scopeSlotNames,
|
|
||||||
scopeSlotIsModule,
|
|
||||||
localSlotNames,
|
|
||||||
localSlotMutables
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1700,15 +1646,6 @@ class BytecodeCompiler(
|
|||||||
updateNameObjClassFromSlot(nameTarget, slot)
|
updateNameObjClassFromSlot(nameTarget, slot)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
val listTarget = ref.target as? ListLiteralRef
|
|
||||||
if (listTarget != null) {
|
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
|
||||||
val valueObj = ensureObjSlot(value)
|
|
||||||
val declId = builder.addConst(BytecodeConst.DestructureAssign(listTarget, callSitePos()))
|
|
||||||
builder.emit(Opcode.ASSIGN_DESTRUCTURE, declId, valueObj.slot)
|
|
||||||
updateSlotType(valueObj.slot, SlotType.OBJ)
|
|
||||||
return CompiledValue(valueObj.slot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
val target = ref.target
|
val target = ref.target
|
||||||
if (target is ClassScopeMemberRef) {
|
if (target is ClassScopeMemberRef) {
|
||||||
@ -1752,25 +1689,6 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (isKnownClassReceiver(target.target)) {
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
|
||||||
if (!target.isOptional) {
|
|
||||||
builder.emit(Opcode.SET_CLASS_SCOPE, 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_CLASS_SCOPE, 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]
|
||||||
@ -1969,102 +1887,28 @@ 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)
|
val receiverClass = resolveReceiverClass(fieldTarget.target)
|
||||||
?: 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
|
||||||
)
|
)
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
|
||||||
val current = allocSlot()
|
|
||||||
val result = allocSlot()
|
|
||||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
|
||||||
if (receiverClass == ObjDynamic.type) {
|
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))
|
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
||||||
if (!fieldTarget.isOptional) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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, current)
|
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, current)
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
builder.emit(objOp, current, rhs.slot, result)
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, result)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
updateSlotType(result, SlotType.OBJ)
|
updateSlotType(result, SlotType.OBJ)
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
return CompiledValue(result, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[fieldTarget.name]
|
throw BytecodeCompileException(
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[fieldTarget.name]
|
"Member assignment requires compile-time receiver type: ${fieldTarget.name}",
|
||||||
if (fieldId == null && methodId == null && isKnownClassReceiver(fieldTarget.target)) {
|
Pos.builtIn
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
)
|
||||||
if (!fieldTarget.isOptional) {
|
|
||||||
builder.emit(Opcode.GET_CLASS_SCOPE, receiver.slot, nameId, current)
|
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
|
||||||
builder.emit(Opcode.SET_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
} 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_CLASS_SCOPE, receiver.slot, nameId, current)
|
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
|
||||||
builder.emit(Opcode.SET_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, result)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
}
|
|
||||||
updateSlotType(result, SlotType.OBJ)
|
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
if (fieldId != null || methodId != null) {
|
|
||||||
if (!fieldTarget.isOptional) {
|
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, current)
|
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
|
||||||
} 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_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, current)
|
|
||||||
builder.emit(objOp, current, rhs.slot, result)
|
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, result)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
}
|
|
||||||
updateSlotType(result, SlotType.OBJ)
|
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
return compileEvalRef(ref)
|
|
||||||
}
|
}
|
||||||
val implicitTarget = ref.target as? ImplicitThisMemberRef
|
val implicitTarget = ref.target as? ImplicitThisMemberRef
|
||||||
if (implicitTarget != null) {
|
if (implicitTarget != null) {
|
||||||
@ -2147,7 +1991,8 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, result)
|
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, result)
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||||
builder.mark(nullLabel)
|
builder.mark(nullLabel)
|
||||||
builder.emit(Opcode.CONST_NULL, result)
|
builder.emit(Opcode.CONST_NULL, current)
|
||||||
|
builder.emit(objOp, current, rhs.slot, result)
|
||||||
builder.mark(endLabel)
|
builder.mark(endLabel)
|
||||||
updateSlotType(result, SlotType.OBJ)
|
updateSlotType(result, SlotType.OBJ)
|
||||||
return CompiledValue(result, SlotType.OBJ)
|
return CompiledValue(result, SlotType.OBJ)
|
||||||
@ -2345,30 +2190,6 @@ class BytecodeCompiler(
|
|||||||
val encodedMethodId = encodeMemberId(receiverClass, methodId)
|
val encodedMethodId = encodeMemberId(receiverClass, methodId)
|
||||||
val receiver = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
||||||
val dst = allocSlot()
|
val dst = allocSlot()
|
||||||
if (fieldId == null && methodId == null && isKnownClassReceiver(ref.target)) {
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
|
||||||
if (!ref.isOptional) {
|
|
||||||
builder.emit(Opcode.GET_CLASS_SCOPE, 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_CLASS_SCOPE, 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)
|
|
||||||
}
|
|
||||||
if (fieldId != null || methodId != null) {
|
if (fieldId != null || methodId != null) {
|
||||||
if (!ref.isOptional) {
|
if (!ref.isOptional) {
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, encodedFieldId ?: -1, encodedMethodId ?: -1, dst)
|
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, encodedFieldId ?: -1, encodedMethodId ?: -1, dst)
|
||||||
@ -2686,15 +2507,13 @@ class BytecodeCompiler(
|
|||||||
val boxed = allocSlot()
|
val boxed = allocSlot()
|
||||||
builder.emit(Opcode.BOX_OBJ, current, boxed)
|
builder.emit(Opcode.BOX_OBJ, current, boxed)
|
||||||
if (wantResult && ref.isPost) {
|
if (wantResult && ref.isPost) {
|
||||||
val old = allocSlot()
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, boxed, old)
|
|
||||||
val result = allocSlot()
|
val result = allocSlot()
|
||||||
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, boxed, oneSlot, result)
|
builder.emit(op, boxed, oneSlot, result)
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, boxed)
|
builder.emit(Opcode.MOVE_OBJ, result, boxed)
|
||||||
emitStoreToAddr(boxed, addrSlot, SlotType.OBJ)
|
emitStoreToAddr(boxed, addrSlot, SlotType.OBJ)
|
||||||
updateSlotType(slot, SlotType.OBJ)
|
updateSlotType(slot, SlotType.OBJ)
|
||||||
CompiledValue(old, SlotType.OBJ)
|
CompiledValue(boxed, SlotType.OBJ)
|
||||||
} else {
|
} else {
|
||||||
val result = allocSlot()
|
val result = allocSlot()
|
||||||
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
|
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
|
||||||
@ -2874,6 +2693,7 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
val fieldTarget = ref.target as? FieldRef
|
val fieldTarget = ref.target as? FieldRef
|
||||||
if (fieldTarget != null) {
|
if (fieldTarget != null) {
|
||||||
|
if (fieldTarget.isOptional) return null
|
||||||
val receiverClass = resolveReceiverClass(fieldTarget.target)
|
val receiverClass = resolveReceiverClass(fieldTarget.target)
|
||||||
?: throw BytecodeCompileException(
|
?: throw BytecodeCompileException(
|
||||||
"Member access requires compile-time receiver type: ${fieldTarget.name}",
|
"Member access requires compile-time receiver type: ${fieldTarget.name}",
|
||||||
@ -2882,45 +2702,6 @@ class BytecodeCompiler(
|
|||||||
if (receiverClass == ObjDynamic.type) {
|
if (receiverClass == ObjDynamic.type) {
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
||||||
val resultSlot = allocSlot()
|
|
||||||
if (fieldTarget.isOptional) {
|
|
||||||
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))
|
|
||||||
)
|
|
||||||
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)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
|
||||||
} else {
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, resultSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
updateSlotType(resultSlot, SlotType.OBJ)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, current)
|
builder.emit(Opcode.GET_DYNAMIC_MEMBER, receiver.slot, nameId, current)
|
||||||
updateSlotType(current, SlotType.OBJ)
|
updateSlotType(current, SlotType.OBJ)
|
||||||
@ -2935,121 +2716,16 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.MOVE_OBJ, current, old)
|
builder.emit(Opcode.MOVE_OBJ, current, old)
|
||||||
builder.emit(op, current, oneSlot, result)
|
builder.emit(op, current, oneSlot, result)
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
return CompiledValue(old, SlotType.OBJ)
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
}
|
||||||
builder.emit(op, current, oneSlot, result)
|
builder.emit(op, current, oneSlot, result)
|
||||||
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
builder.emit(Opcode.SET_DYNAMIC_MEMBER, receiver.slot, nameId, result)
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
return CompiledValue(result, SlotType.OBJ)
|
||||||
return CompiledValue(resultSlot, 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 && isKnownClassReceiver(fieldTarget.target)) {
|
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
|
||||||
val resultSlot = allocSlot()
|
|
||||||
if (fieldTarget.isOptional) {
|
|
||||||
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))
|
|
||||||
)
|
|
||||||
val current = allocSlot()
|
|
||||||
builder.emit(Opcode.GET_CLASS_SCOPE, 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_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
|
||||||
} else {
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, resultSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
updateSlotType(resultSlot, SlotType.OBJ)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val current = allocSlot()
|
|
||||||
builder.emit(Opcode.GET_CLASS_SCOPE, 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_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_CLASS_SCOPE, receiver.slot, nameId, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
if (fieldId == null && methodId == null) return null
|
if (fieldId == null && methodId == null) return null
|
||||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
||||||
val resultSlot = allocSlot()
|
|
||||||
if (fieldTarget.isOptional) {
|
|
||||||
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))
|
|
||||||
)
|
|
||||||
val current = allocSlot()
|
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, 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_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
|
||||||
} else {
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, resultSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
updateSlotType(resultSlot, SlotType.OBJ)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, current)
|
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, current)
|
||||||
updateSlotType(current, SlotType.OBJ)
|
updateSlotType(current, SlotType.OBJ)
|
||||||
@ -3064,55 +2740,16 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.MOVE_OBJ, current, old)
|
builder.emit(Opcode.MOVE_OBJ, current, old)
|
||||||
builder.emit(op, current, oneSlot, result)
|
builder.emit(op, current, oneSlot, result)
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
return CompiledValue(old, SlotType.OBJ)
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
}
|
||||||
builder.emit(op, current, oneSlot, result)
|
builder.emit(op, current, oneSlot, result)
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, result)
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
return CompiledValue(result, SlotType.OBJ)
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val indexTarget = ref.target as? IndexRef ?: return null
|
val indexTarget = ref.target as? IndexRef ?: return null
|
||||||
|
if (indexTarget.optionalRef) return null
|
||||||
val receiver = compileRefWithFallback(indexTarget.targetRef, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(indexTarget.targetRef, null, Pos.builtIn) ?: return null
|
||||||
if (indexTarget.optionalRef) {
|
|
||||||
val resultSlot = allocSlot()
|
|
||||||
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))
|
|
||||||
)
|
|
||||||
val index = compileRefWithFallback(indexTarget.indexRef, null, Pos.builtIn) ?: return null
|
|
||||||
val current = allocSlot()
|
|
||||||
builder.emit(Opcode.GET_INDEX, receiver.slot, index.slot, current)
|
|
||||||
updateSlotType(current, SlotType.OBJ)
|
|
||||||
val oneSlot = allocSlot()
|
|
||||||
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
|
|
||||||
builder.emit(Opcode.CONST_OBJ, oneId, oneSlot)
|
|
||||||
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_INDEX, receiver.slot, index.slot, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, old, resultSlot)
|
|
||||||
} else {
|
|
||||||
builder.emit(op, current, oneSlot, result)
|
|
||||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, result)
|
|
||||||
builder.emit(Opcode.MOVE_OBJ, result, resultSlot)
|
|
||||||
}
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, resultSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val index = compileRefWithFallback(indexTarget.indexRef, null, Pos.builtIn) ?: return null
|
val index = compileRefWithFallback(indexTarget.indexRef, null, Pos.builtIn) ?: return null
|
||||||
val current = allocSlot()
|
val current = allocSlot()
|
||||||
builder.emit(Opcode.GET_INDEX, receiver.slot, index.slot, current)
|
builder.emit(Opcode.GET_INDEX, receiver.slot, index.slot, current)
|
||||||
@ -3455,34 +3092,6 @@ class BytecodeCompiler(
|
|||||||
builder.mark(endLabel)
|
builder.mark(endLabel)
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
if (isKnownClassReceiver(ref.receiver)) {
|
|
||||||
val nameId = builder.addConst(BytecodeConst.StringVal(ref.name))
|
|
||||||
val memberSlot = allocSlot()
|
|
||||||
if (!ref.isOptional) {
|
|
||||||
builder.emit(Opcode.GET_CLASS_SCOPE, receiver.slot, nameId, memberSlot)
|
|
||||||
} 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_CLASS_SCOPE, receiver.slot, nameId, memberSlot)
|
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
|
||||||
builder.mark(nullLabel)
|
|
||||||
builder.emit(Opcode.CONST_NULL, memberSlot)
|
|
||||||
builder.mark(endLabel)
|
|
||||||
}
|
|
||||||
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
|
||||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
|
||||||
setPos(callPos)
|
|
||||||
builder.emit(Opcode.CALL_SLOT, memberSlot, args.base, encodedCount, dst)
|
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
val extSlot = resolveExtensionCallableSlot(receiverClass, ref.name)
|
val extSlot = resolveExtensionCallableSlot(receiverClass, ref.name)
|
||||||
?: throw BytecodeCompileException(
|
?: throw BytecodeCompileException(
|
||||||
"Unknown member ${ref.name} on ${receiverClass.className}",
|
"Unknown member ${ref.name} on ${receiverClass.className}",
|
||||||
@ -3867,17 +3476,6 @@ class BytecodeCompiler(
|
|||||||
throw BytecodeCompileException("Unsupported statement in bytecode: $stmtName", stmt.pos)
|
throw BytecodeCompileException("Unsupported statement in bytecode: $stmtName", stmt.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitStatementCall(stmt: Statement): CompiledValue {
|
|
||||||
val constId = builder.addConst(BytecodeConst.ObjRef(stmt))
|
|
||||||
val calleeSlot = allocSlot()
|
|
||||||
builder.emit(Opcode.CONST_OBJ, constId, calleeSlot)
|
|
||||||
updateSlotType(calleeSlot, SlotType.OBJ)
|
|
||||||
val dst = allocSlot()
|
|
||||||
builder.emit(Opcode.CALL_SLOT, calleeSlot, 0, 0, dst)
|
|
||||||
updateSlotType(dst, SlotType.OBJ)
|
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
setPos(target.pos)
|
setPos(target.pos)
|
||||||
@ -3911,9 +3509,9 @@ class BytecodeCompiler(
|
|||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> emitStatementCall(target)
|
is net.sergeych.lyng.ClassDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> emitStatementCall(target)
|
is net.sergeych.lyng.FunctionDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitStatementCall(target)
|
is net.sergeych.lyng.EnumDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
||||||
is net.sergeych.lyng.WhenStatement -> compileWhen(target, true)
|
is net.sergeych.lyng.WhenStatement -> compileWhen(target, true)
|
||||||
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
||||||
@ -3938,9 +3536,6 @@ class BytecodeCompiler(
|
|||||||
is VarDeclStatement -> emitVarDecl(target)
|
is VarDeclStatement -> emitVarDecl(target)
|
||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||||
is IfStatement -> compileIfStatement(target)
|
is IfStatement -> compileIfStatement(target)
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> emitStatementCall(target)
|
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> emitStatementCall(target)
|
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitStatementCall(target)
|
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
val resultSlot = emitForIn(target, false) ?: return null
|
val resultSlot = emitForIn(target, false) ?: return null
|
||||||
CompiledValue(resultSlot, SlotType.OBJ)
|
CompiledValue(resultSlot, SlotType.OBJ)
|
||||||
@ -5391,9 +4986,6 @@ class BytecodeCompiler(
|
|||||||
private fun resolveReceiverClass(ref: ObjRef): ObjClass? {
|
private fun resolveReceiverClass(ref: ObjRef): ObjClass? {
|
||||||
return when (ref) {
|
return when (ref) {
|
||||||
is LocalSlotRef -> {
|
is LocalSlotRef -> {
|
||||||
if (knownObjectNames.contains(ref.name)) {
|
|
||||||
return nameObjClass[ref.name] ?: ObjDynamic.type
|
|
||||||
}
|
|
||||||
val slot = resolveSlot(ref)
|
val slot = resolveSlot(ref)
|
||||||
val fromSlot = slot?.let { slotObjClass[it] }
|
val fromSlot = slot?.let { slotObjClass[it] }
|
||||||
fromSlot
|
fromSlot
|
||||||
@ -5410,9 +5002,6 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is LocalVarRef -> {
|
is LocalVarRef -> {
|
||||||
if (knownObjectNames.contains(ref.name)) {
|
|
||||||
return nameObjClass[ref.name] ?: ObjDynamic.type
|
|
||||||
}
|
|
||||||
val fromSlot = resolveDirectNameSlot(ref.name)?.let { slotObjClass[it.slot] }
|
val fromSlot = resolveDirectNameSlot(ref.name)?.let { slotObjClass[it.slot] }
|
||||||
if (fromSlot != null) return fromSlot
|
if (fromSlot != null) return fromSlot
|
||||||
val key = localSlotInfoMap.entries.firstOrNull { it.value.name == ref.name }?.key
|
val key = localSlotInfoMap.entries.firstOrNull { it.value.name == ref.name }?.key
|
||||||
@ -5457,14 +5046,6 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isKnownClassReceiver(ref: ObjRef): Boolean {
|
|
||||||
return when (ref) {
|
|
||||||
is LocalVarRef -> knownClassNames.contains(ref.name) && !knownObjectNames.contains(ref.name)
|
|
||||||
is LocalSlotRef -> knownClassNames.contains(ref.name) && !knownObjectNames.contains(ref.name)
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isAllowedObjectMember(memberName: String): Boolean {
|
private fun isAllowedObjectMember(memberName: String): Boolean {
|
||||||
return when (memberName) {
|
return when (memberName) {
|
||||||
"toString",
|
"toString",
|
||||||
@ -5568,12 +5149,8 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
private fun inferCallReturnClass(ref: CallRef): ObjClass? {
|
private fun inferCallReturnClass(ref: CallRef): ObjClass? {
|
||||||
return when (val target = ref.target) {
|
return when (val target = ref.target) {
|
||||||
is LocalSlotRef -> callableReturnTypeByScopeId[target.scopeId]?.get(target.slot)
|
is LocalSlotRef -> nameObjClass[target.name] ?: resolveTypeNameClass(target.name)
|
||||||
?: nameObjClass[target.name]
|
is LocalVarRef -> nameObjClass[target.name] ?: resolveTypeNameClass(target.name)
|
||||||
?: resolveTypeNameClass(target.name)
|
|
||||||
is LocalVarRef -> callableReturnTypeByName[target.name]
|
|
||||||
?: nameObjClass[target.name]
|
|
||||||
?: resolveTypeNameClass(target.name)
|
|
||||||
is ConstRef -> target.constValue as? ObjClass
|
is ConstRef -> target.constValue as? ObjClass
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@ -5637,16 +5214,6 @@ class BytecodeCompiler(
|
|||||||
private fun inferFieldReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
|
private fun inferFieldReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
|
||||||
if (targetClass == null) return null
|
if (targetClass == null) return null
|
||||||
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
||||||
classFieldTypesByName[targetClass.className]?.get(name)?.let { return it }
|
|
||||||
enumEntriesByName[targetClass.className]?.let { entries ->
|
|
||||||
return when {
|
|
||||||
name == "entries" -> ObjList.type
|
|
||||||
name == "name" -> ObjString.type
|
|
||||||
name == "ordinal" -> ObjInt.type
|
|
||||||
entries.contains(name) -> targetClass
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjInstant.type && (name == "distantFuture" || name == "distantPast")) {
|
if (targetClass == ObjInstant.type && (name == "distantFuture" || name == "distantPast")) {
|
||||||
return ObjInstant.type
|
return ObjInstant.type
|
||||||
}
|
}
|
||||||
@ -6439,11 +6006,7 @@ class BytecodeCompiler(
|
|||||||
is CastRef -> containsValueFnRef(ref.castValueRef()) || containsValueFnRef(ref.castTypeRef())
|
is CastRef -> containsValueFnRef(ref.castValueRef()) || containsValueFnRef(ref.castTypeRef())
|
||||||
is AssignRef -> {
|
is AssignRef -> {
|
||||||
val target = assignTarget(ref)
|
val target = assignTarget(ref)
|
||||||
if (target != null) {
|
(target != null && containsValueFnRef(target)) || containsValueFnRef(assignValue(ref))
|
||||||
containsValueFnRef(target) || containsValueFnRef(assignValue(ref))
|
|
||||||
} else {
|
|
||||||
containsValueFnRef(ref.target) || containsValueFnRef(assignValue(ref))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is AssignOpRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
is AssignOpRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||||
is AssignIfNullRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
is AssignIfNullRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||||
|
|||||||
@ -61,10 +61,6 @@ sealed class BytecodeConst {
|
|||||||
val isTransient: Boolean,
|
val isTransient: Boolean,
|
||||||
val pos: Pos,
|
val pos: Pos,
|
||||||
) : BytecodeConst()
|
) : BytecodeConst()
|
||||||
data class DestructureAssign(
|
|
||||||
val pattern: ListLiteralRef,
|
|
||||||
val pos: Pos,
|
|
||||||
) : BytecodeConst()
|
|
||||||
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
||||||
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,11 +45,6 @@ class BytecodeStatement private constructor(
|
|||||||
moduleScopeId: Int? = null,
|
moduleScopeId: Int? = null,
|
||||||
slotTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
slotTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
||||||
knownNameObjClass: Map<String, ObjClass> = emptyMap(),
|
knownNameObjClass: Map<String, ObjClass> = emptyMap(),
|
||||||
knownObjectNames: Set<String> = emptySet(),
|
|
||||||
classFieldTypesByName: Map<String, Map<String, ObjClass>> = emptyMap(),
|
|
||||||
enumEntriesByName: Map<String, List<String>> = emptyMap(),
|
|
||||||
callableReturnTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
|
||||||
callableReturnTypeByName: Map<String, ObjClass> = emptyMap(),
|
|
||||||
): Statement {
|
): Statement {
|
||||||
if (statement is BytecodeStatement) return statement
|
if (statement is BytecodeStatement) return statement
|
||||||
val hasUnsupported = containsUnsupportedStatement(statement)
|
val hasUnsupported = containsUnsupportedStatement(statement)
|
||||||
@ -68,12 +63,7 @@ class BytecodeStatement private constructor(
|
|||||||
allowedScopeNames = allowedScopeNames,
|
allowedScopeNames = allowedScopeNames,
|
||||||
moduleScopeId = moduleScopeId,
|
moduleScopeId = moduleScopeId,
|
||||||
slotTypeByScopeId = slotTypeByScopeId,
|
slotTypeByScopeId = slotTypeByScopeId,
|
||||||
knownNameObjClass = knownNameObjClass,
|
knownNameObjClass = knownNameObjClass
|
||||||
knownObjectNames = knownObjectNames,
|
|
||||||
classFieldTypesByName = classFieldTypesByName,
|
|
||||||
enumEntriesByName = enumEntriesByName,
|
|
||||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
|
||||||
callableReturnTypeByName = callableReturnTypeByName
|
|
||||||
)
|
)
|
||||||
val compiled = compiler.compileStatement(nameHint, statement)
|
val compiled = compiler.compileStatement(nameHint, statement)
|
||||||
val fn = compiled ?: throw BytecodeCompileException(
|
val fn = compiled ?: throw BytecodeCompileException(
|
||||||
|
|||||||
@ -147,8 +147,7 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
||||||
Opcode.ASSIGN_DESTRUCTURE ->
|
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
@ -399,7 +398,6 @@ class CmdBuilder {
|
|||||||
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
||||||
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
||||||
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
|
||||||
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||||
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.CALL_DYNAMIC_MEMBER -> CmdCallDynamicMember(operands[0], operands[1], operands[2], operands[3], operands[4])
|
Opcode.CALL_DYNAMIC_MEMBER -> CmdCallDynamicMember(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||||
|
|||||||
@ -193,7 +193,6 @@ object CmdDisassembler {
|
|||||||
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
|
||||||
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdCallDynamicMember -> Opcode.CALL_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallDynamicMember -> Opcode.CALL_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
@ -255,8 +254,7 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
||||||
Opcode.ASSIGN_DESTRUCTURE ->
|
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
|
|||||||
@ -240,9 +240,7 @@ class CmdAssertIs(internal val objSlot: Int, internal val typeSlot: Int) : Cmd()
|
|||||||
"${typeObj.inspect(frame.ensureScope())} is not the class instance"
|
"${typeObj.inspect(frame.ensureScope())} is not the class instance"
|
||||||
)
|
)
|
||||||
if (!obj.isInstanceOf(clazz)) {
|
if (!obj.isInstanceOf(clazz)) {
|
||||||
frame.ensureScope().raiseClassCastError(
|
frame.ensureScope().raiseClassCastError("expected ${clazz.className}, got ${obj.objClass.className}")
|
||||||
"Cannot cast ${obj.objClass.className} to ${clazz.className}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1272,26 +1270,7 @@ class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cm
|
|||||||
scope.updateSlotFor(name, immutableRec)
|
scope.updateSlotFor(name, immutableRec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (slot >= frame.fn.scopeSlotCount) {
|
frame.storeObjResult(slot, ObjVoid)
|
||||||
frame.storeObjResult(slot, ObjVoid)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdAssignDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureAssign
|
|
||||||
?: error("ASSIGN_DESTRUCTURE expects DestructureAssign at $constId")
|
|
||||||
val value = frame.slotToObj(slot)
|
|
||||||
decl.pattern.setAt(decl.pos, frame.ensureScope(), value)
|
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(slot, value)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1317,14 +1296,6 @@ class CmdDeclExtProperty(internal val constId: Int, internal val slot: Int) : Cm
|
|||||||
type = ObjRecord.Type.Property
|
type = ObjRecord.Type.Property
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val getterName = extensionPropertyGetterName(decl.extTypeName, decl.property.name)
|
|
||||||
val getterWrapper = ObjExtensionPropertyGetterCallable(decl.property.name, decl.property)
|
|
||||||
frame.ensureScope().addItem(getterName, false, getterWrapper, decl.visibility, recordType = ObjRecord.Type.Fun)
|
|
||||||
if (decl.property.setter != null) {
|
|
||||||
val setterName = extensionPropertySetterName(decl.extTypeName, decl.property.name)
|
|
||||||
val setterWrapper = ObjExtensionPropertySetterCallable(decl.property.name, decl.property)
|
|
||||||
frame.ensureScope().addItem(setterName, false, setterWrapper, decl.visibility, recordType = ObjRecord.Type.Fun)
|
|
||||||
}
|
|
||||||
frame.setObj(slot, decl.property)
|
frame.setObj(slot, decl.property)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1478,12 +1449,7 @@ class CmdGetMemberSlot(
|
|||||||
}
|
}
|
||||||
} else null
|
} else null
|
||||||
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
||||||
val rawName = rec.memberName ?: "<member>"
|
val name = rec.memberName ?: "<member>"
|
||||||
val name = if (receiver is ObjInstance && rawName.contains("::")) {
|
|
||||||
rawName.substringAfterLast("::")
|
|
||||||
} else {
|
|
||||||
rawName
|
|
||||||
}
|
|
||||||
suspend fun autoCallIfMethod(resolved: ObjRecord, recv: Obj): Obj {
|
suspend fun autoCallIfMethod(resolved: ObjRecord, recv: Obj): Obj {
|
||||||
return if (resolved.type == ObjRecord.Type.Fun && !resolved.isAbstract) {
|
return if (resolved.type == ObjRecord.Type.Fun && !resolved.isAbstract) {
|
||||||
resolved.value.invoke(frame.ensureScope(), resolved.receiver ?: recv, Arguments.EMPTY, resolved.declaringClass)
|
resolved.value.invoke(frame.ensureScope(), resolved.receiver ?: recv, Arguments.EMPTY, resolved.declaringClass)
|
||||||
@ -1532,17 +1498,12 @@ class CmdSetMemberSlot(
|
|||||||
}
|
}
|
||||||
} else null
|
} else null
|
||||||
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
||||||
val rawName = rec.memberName ?: "<member>"
|
val name = rec.memberName ?: "<member>"
|
||||||
val name = if (receiver is ObjInstance && rawName.contains("::")) {
|
|
||||||
rawName.substringAfterLast("::")
|
|
||||||
} else {
|
|
||||||
rawName
|
|
||||||
}
|
|
||||||
if (receiver is ObjQualifiedView) {
|
if (receiver is ObjQualifiedView) {
|
||||||
receiver.writeField(frame.ensureScope(), name, frame.slotToObj(valueSlot))
|
receiver.writeField(frame.ensureScope(), name, frame.slotToObj(valueSlot))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
receiver.writeField(frame.ensureScope(), name, frame.slotToObj(valueSlot))
|
frame.ensureScope().assign(rec, name, frame.slotToObj(valueSlot))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2422,10 +2383,10 @@ class CmdFrame(
|
|||||||
val direct = record.value
|
val direct = record.value
|
||||||
if (direct is FrameSlotRef) return direct.read()
|
if (direct is FrameSlotRef) return direct.read()
|
||||||
val name = fn.scopeSlotNames[slot]
|
val name = fn.scopeSlotNames[slot]
|
||||||
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
|
||||||
return target.resolve(record, name)
|
|
||||||
}
|
|
||||||
if (direct !== ObjUnset) {
|
if (direct !== ObjUnset) {
|
||||||
|
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
||||||
|
return target.resolve(record, name)
|
||||||
|
}
|
||||||
return direct
|
return direct
|
||||||
}
|
}
|
||||||
if (name == null) return record.value
|
if (name == null) return record.value
|
||||||
@ -2444,10 +2405,10 @@ class CmdFrame(
|
|||||||
if (direct is FrameSlotRef) return direct.read()
|
if (direct is FrameSlotRef) return direct.read()
|
||||||
val slotId = addrScopeSlots[addrSlot]
|
val slotId = addrScopeSlots[addrSlot]
|
||||||
val name = fn.scopeSlotNames.getOrNull(slotId)
|
val name = fn.scopeSlotNames.getOrNull(slotId)
|
||||||
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
|
||||||
return target.resolve(record, name)
|
|
||||||
}
|
|
||||||
if (direct !== ObjUnset) {
|
if (direct !== ObjUnset) {
|
||||||
|
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
||||||
|
return target.resolve(record, name)
|
||||||
|
}
|
||||||
return direct
|
return direct
|
||||||
}
|
}
|
||||||
if (name == null) return record.value
|
if (name == null) return record.value
|
||||||
|
|||||||
@ -132,7 +132,6 @@ enum class Opcode(val code: Int) {
|
|||||||
CLEAR_PENDING_THROWABLE(0x8F),
|
CLEAR_PENDING_THROWABLE(0x8F),
|
||||||
|
|
||||||
CALL_DIRECT(0x90),
|
CALL_DIRECT(0x90),
|
||||||
ASSIGN_DESTRUCTURE(0x91),
|
|
||||||
CALL_MEMBER_SLOT(0x92),
|
CALL_MEMBER_SLOT(0x92),
|
||||||
CALL_SLOT(0x93),
|
CALL_SLOT(0x93),
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user