Reuse value is ISTORE if expected type is the same, otherwise, create
new value
This commit is contained in:
+26
-11
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.codegen.coroutines
|
|||||||
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
|
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.org.objectweb.asm.Handle
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
@@ -248,32 +247,48 @@ private class SpilledVariableFieldTypesInterpreter(
|
|||||||
|
|
||||||
// ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
|
// ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
|
||||||
// ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
|
// ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
|
||||||
override fun copyOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? =
|
override fun copyOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? {
|
||||||
when (insn.opcode) {
|
return when (insn.opcode) {
|
||||||
// If same ICONST is stored into several slots, thay can have different types
|
// If same ICONST is stored into several slots, thay can have different types
|
||||||
// For example,
|
// For example,
|
||||||
// val b: Byte = 1
|
// val b: Byte = 1
|
||||||
// val i: Int = b.toInt()
|
// val i: Int = b.toInt()
|
||||||
// In this case, `b` and `i` have the same source, but different types.
|
// In this case, `b` and `i` have the same source, but different types.
|
||||||
// The example also shows, that the types should be `I`.
|
// The example also shows, that the types should be `I`.
|
||||||
ISTORE -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
|
ISTORE -> {
|
||||||
|
findTypeFromLvt((insn as VarInsnNode).`var`, insn)?.let {
|
||||||
|
if (it == value?.type) return value
|
||||||
|
}
|
||||||
|
var current: AbstractInsnNode? = insn
|
||||||
|
while (current != null && current !is LabelNode) {
|
||||||
|
current = current.next
|
||||||
|
}
|
||||||
|
while (current is LabelNode) {
|
||||||
|
findTypeFromLvt((insn as VarInsnNode).`var`, current)?.let {
|
||||||
|
if (it == value?.type) return value
|
||||||
|
}
|
||||||
|
current = current.next
|
||||||
|
}
|
||||||
|
SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
|
||||||
|
}
|
||||||
// Sometimes we cannot get the type from the usage only
|
// Sometimes we cannot get the type from the usage only
|
||||||
// For example,
|
// For example,
|
||||||
// val c = '1'
|
// val c = '1'
|
||||||
// if (c == '2) ...
|
// if (c == '2) ...
|
||||||
// In this case, update the type using information from LVT
|
// In this case, update the type using information from LVT
|
||||||
ILOAD -> {
|
ILOAD -> {
|
||||||
methodNode.localVariables.find { local ->
|
findTypeFromLvt((insn as VarInsnNode).`var`, insn)?.let { value?.type = it }
|
||||||
local.index == (insn as VarInsnNode).`var` &&
|
|
||||||
methodNode.instructions.indexOf(local.start) < methodNode.instructions.indexOf(insn) &&
|
|
||||||
methodNode.instructions.indexOf(insn) < methodNode.instructions.indexOf(local.end)
|
|
||||||
}?.let { local ->
|
|
||||||
value?.type = Type.getType(local.desc)
|
|
||||||
}
|
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
else -> value
|
else -> value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findTypeFromLvt(index: Int, insn: AbstractInsnNode): Type? = methodNode.localVariables.find { local ->
|
||||||
|
local.index == index &&
|
||||||
|
methodNode.instructions.indexOf(local.start) <= methodNode.instructions.indexOf(insn) &&
|
||||||
|
methodNode.instructions.indexOf(insn) < methodNode.instructions.indexOf(local.end)
|
||||||
|
}?.let { Type.getType(it.desc) }
|
||||||
|
|
||||||
// ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
|
// ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
|
||||||
// ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
|
// ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
|
||||||
|
|||||||
Reference in New Issue
Block a user