Compile this-slot method calls to bytecode
This commit is contained in:
parent
951ce989a6
commit
aebe0890d8
@ -176,8 +176,8 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
is LocalVarRef -> compileNameLookup(ref.name)
|
is LocalVarRef -> compileNameLookup(ref.name)
|
||||||
is ValueFnRef -> compileEvalRef(ref)
|
is ValueFnRef -> compileEvalRef(ref)
|
||||||
is ListLiteralRef -> compileEvalRef(ref)
|
is ListLiteralRef -> compileListLiteral(ref)
|
||||||
is ThisMethodSlotCallRef -> compileEvalRef(ref)
|
is ThisMethodSlotCallRef -> compileThisMethodSlotCall(ref)
|
||||||
is StatementRef -> {
|
is StatementRef -> {
|
||||||
val constId = builder.addConst(BytecodeConst.StatementVal(ref.statement))
|
val constId = builder.addConst(BytecodeConst.StatementVal(ref.statement))
|
||||||
val slot = allocSlot()
|
val slot = allocSlot()
|
||||||
@ -246,6 +246,29 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, SlotType.OBJ)
|
return CompiledValue(slot, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileListLiteral(ref: ListLiteralRef): CompiledValue? {
|
||||||
|
val entries = ref.entries()
|
||||||
|
val count = entries.size
|
||||||
|
val baseSlot = nextSlot
|
||||||
|
val entrySlots = IntArray(count) { allocSlot() }
|
||||||
|
val spreads = ArrayList<Boolean>(count)
|
||||||
|
for ((index, entry) in entries.withIndex()) {
|
||||||
|
val value = when (entry) {
|
||||||
|
is net.sergeych.lyng.ListEntry.Element ->
|
||||||
|
compileRefWithFallback(entry.ref, null, Pos.builtIn)
|
||||||
|
is net.sergeych.lyng.ListEntry.Spread ->
|
||||||
|
compileRefWithFallback(entry.ref, null, Pos.builtIn)
|
||||||
|
} ?: return null
|
||||||
|
emitMove(value, entrySlots[index])
|
||||||
|
spreads.add(entry is net.sergeych.lyng.ListEntry.Spread)
|
||||||
|
}
|
||||||
|
val planId = builder.addConst(BytecodeConst.ListLiteralPlan(spreads))
|
||||||
|
val dst = allocSlot()
|
||||||
|
builder.emit(Opcode.LIST_LITERAL, planId, baseSlot, count, dst)
|
||||||
|
updateSlotType(dst, SlotType.OBJ)
|
||||||
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileUnary(ref: UnaryOpRef): CompiledValue? {
|
private fun compileUnary(ref: UnaryOpRef): CompiledValue? {
|
||||||
val a = compileRef(unaryOperand(ref)) ?: return null
|
val a = compileRef(unaryOperand(ref)) ?: return null
|
||||||
val out = allocSlot()
|
val out = allocSlot()
|
||||||
@ -1484,6 +1507,37 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(dst, SlotType.OBJ)
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileThisMethodSlotCall(ref: ThisMethodSlotCallRef): CompiledValue? {
|
||||||
|
val receiver = compileNameLookup("this")
|
||||||
|
val methodId = builder.addConst(BytecodeConst.StringVal(ref.methodName()))
|
||||||
|
if (methodId > 0xFFFF) return null
|
||||||
|
val dst = allocSlot()
|
||||||
|
if (!ref.optionalInvoke()) {
|
||||||
|
val args = compileCallArgs(ref.arguments(), ref.hasTailBlock()) ?: return null
|
||||||
|
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||||
|
builder.emit(Opcode.CALL_VIRTUAL, receiver.slot, methodId, 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))
|
||||||
|
)
|
||||||
|
val args = compileCallArgs(ref.arguments(), ref.hasTailBlock()) ?: return null
|
||||||
|
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||||
|
builder.emit(Opcode.CALL_VIRTUAL, receiver.slot, methodId, 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)
|
||||||
|
}
|
||||||
|
|
||||||
private data class CallArgs(val base: Int, val count: Int, val planId: Int?)
|
private data class CallArgs(val base: Int, val count: Int, val planId: Int?)
|
||||||
|
|
||||||
private fun compileCallArgs(args: List<ParsedArgument>, tailBlock: Boolean): CallArgs? {
|
private fun compileCallArgs(args: List<ParsedArgument>, tailBlock: Boolean): CallArgs? {
|
||||||
|
|||||||
@ -1865,6 +1865,11 @@ class ThisMethodSlotCallRef(
|
|||||||
private val tailBlock: Boolean,
|
private val tailBlock: Boolean,
|
||||||
private val isOptional: Boolean
|
private val isOptional: Boolean
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
|
internal fun methodName(): String = name
|
||||||
|
internal fun arguments(): List<ParsedArgument> = args
|
||||||
|
internal fun hasTailBlock(): Boolean = tailBlock
|
||||||
|
internal fun optionalInvoke(): Boolean = isOptional
|
||||||
|
|
||||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
@ -2516,6 +2521,8 @@ class LocalSlotRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
||||||
|
internal fun entries(): List<ListEntry> = entries
|
||||||
|
|
||||||
override fun forEachVariable(block: (String) -> Unit) {
|
override fun forEachVariable(block: (String) -> Unit) {
|
||||||
for (e in entries) {
|
for (e in entries) {
|
||||||
when (e) {
|
when (e) {
|
||||||
@ -2665,9 +2672,9 @@ class RangeRef(
|
|||||||
|
|
||||||
/** Assignment if null op: target ?= value */
|
/** Assignment if null op: target ?= value */
|
||||||
class AssignIfNullRef(
|
class AssignIfNullRef(
|
||||||
private val target: ObjRef,
|
internal val target: ObjRef,
|
||||||
private val value: ObjRef,
|
internal val value: ObjRef,
|
||||||
private val atPos: Pos,
|
internal val atPos: Pos,
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
return evalValue(scope).asReadonly
|
return evalValue(scope).asReadonly
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user