Review fixes
This commit is contained in:
@@ -59,7 +59,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
|||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import java.io.IOException
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class InlineCodegen(
|
class InlineCodegen(
|
||||||
@@ -503,7 +502,7 @@ class InlineCodegen(
|
|||||||
assert(value is StackValue.Constant) { "Additional default method argument should be constant, but " + value }
|
assert(value is StackValue.Constant) { "Additional default method argument should be constant, but " + value }
|
||||||
val constantValue = (value as StackValue.Constant).value
|
val constantValue = (value as StackValue.Constant).value
|
||||||
if (kind === ValueKind.DEFAULT_MASK) {
|
if (kind === ValueKind.DEFAULT_MASK) {
|
||||||
assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue!! }
|
assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue }
|
||||||
maskValues.add(constantValue as Int)
|
maskValues.add(constantValue as Int)
|
||||||
if (maskStartIndex == -1) {
|
if (maskStartIndex == -1) {
|
||||||
maskStartIndex = invocationParamBuilder.nextParameterOffset
|
maskStartIndex = invocationParamBuilder.nextParameterOffset
|
||||||
@@ -556,11 +555,8 @@ class InlineCodegen(
|
|||||||
|
|
||||||
val frameMap = finallyCodegen.frameMap
|
val frameMap = finallyCodegen.frameMap
|
||||||
val mark = frameMap.mark()
|
val mark = frameMap.mark()
|
||||||
var marker = -1
|
val marker = processor.localVarsMetaInfo.currentIntervals.maxBy { it.node.index }?.node?.index?.plus(1) ?: -1
|
||||||
val intervals = processor.localVarsMetaInfo.currentIntervals
|
|
||||||
for (interval in intervals) {
|
|
||||||
marker = Math.max(interval.node.index + 1, marker)
|
|
||||||
}
|
|
||||||
while (frameMap.currentSize < Math.max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) {
|
while (frameMap.currentSize < Math.max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) {
|
||||||
frameMap.enterTemp(Type.INT_TYPE)
|
frameMap.enterTemp(Type.INT_TYPE)
|
||||||
}
|
}
|
||||||
@@ -602,13 +598,11 @@ class InlineCodegen(
|
|||||||
private fun getMemberScope(functionOrAccessor: FunctionDescriptor): MemberScope? {
|
private fun getMemberScope(functionOrAccessor: FunctionDescriptor): MemberScope? {
|
||||||
val callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor)
|
val callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor)
|
||||||
val classOrPackageFragment = callableMemberDescriptor.containingDeclaration
|
val classOrPackageFragment = callableMemberDescriptor.containingDeclaration
|
||||||
if (classOrPackageFragment is ClassDescriptor) {
|
return when (classOrPackageFragment) {
|
||||||
return classOrPackageFragment.unsubstitutedMemberScope
|
is ClassDescriptor -> classOrPackageFragment.unsubstitutedMemberScope
|
||||||
|
is PackageFragmentDescriptor -> classOrPackageFragment.getMemberScope()
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
else if (classOrPackageFragment is PackageFragmentDescriptor) {
|
|
||||||
return classOrPackageFragment.getMemberScope()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun createMethodNode(
|
internal fun createMethodNode(
|
||||||
@@ -620,14 +614,12 @@ class InlineCodegen(
|
|||||||
resolvedCall: ResolvedCall<*>?
|
resolvedCall: ResolvedCall<*>?
|
||||||
): SMAPAndMethodNode {
|
): SMAPAndMethodNode {
|
||||||
if (isSpecialEnumMethod(functionDescriptor)) {
|
if (isSpecialEnumMethod(functionDescriptor)) {
|
||||||
assert(resolvedCall != null) { "Resolved call for $functionDescriptor should be not null" }
|
|
||||||
val arguments = resolvedCall!!.typeArguments
|
val arguments = resolvedCall!!.typeArguments
|
||||||
assert(arguments.size == 1) { "Resolved call for $functionDescriptor should have 1 type argument" }
|
|
||||||
|
|
||||||
val node = createSpecialEnumMethodBody(
|
val node = createSpecialEnumMethodBody(
|
||||||
codegen,
|
codegen,
|
||||||
functionDescriptor.name.asString(),
|
functionDescriptor.name.asString(),
|
||||||
arguments.keys.iterator().next().defaultType,
|
arguments.keys.single().defaultType,
|
||||||
codegen.state.typeMapper
|
codegen.state.typeMapper
|
||||||
)
|
)
|
||||||
return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1))
|
return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1))
|
||||||
@@ -655,8 +647,8 @@ class InlineCodegen(
|
|||||||
|
|
||||||
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId
|
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId
|
||||||
) {
|
) {
|
||||||
val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod) ?: throw IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor)
|
doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
|
||||||
result
|
?: throw IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.node))
|
return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.node))
|
||||||
@@ -664,20 +656,15 @@ class InlineCodegen(
|
|||||||
|
|
||||||
private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor {
|
private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor {
|
||||||
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
|
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
|
||||||
if (directMember is ImportedFromObjectCallableDescriptor<*>) {
|
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
|
||||||
return (directMember as ImportedFromObjectCallableDescriptor<*>).callableFromObject
|
|
||||||
}
|
|
||||||
return directMember
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cloneMethodNode(methodNode: MethodNode): MethodNode {
|
private fun cloneMethodNode(methodNode: MethodNode): MethodNode {
|
||||||
methodNode.instructions.resetLabels()
|
methodNode.instructions.resetLabels()
|
||||||
val result = MethodNode(
|
return MethodNode(
|
||||||
API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature,
|
API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature,
|
||||||
ArrayUtil.toStringArray(methodNode.exceptions)
|
ArrayUtil.toStringArray(methodNode.exceptions)
|
||||||
)
|
).also(methodNode::accept)
|
||||||
methodNode.accept(result)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doCreateMethodNodeFromCompiled(
|
private fun doCreateMethodNodeFromCompiled(
|
||||||
@@ -698,13 +685,8 @@ class InlineCodegen(
|
|||||||
val containerId = containingClasses.implClassId
|
val containerId = containingClasses.implClassId
|
||||||
|
|
||||||
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
||||||
val file = findVirtualFile(state, containerId) ?: throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
findVirtualFile(state, containerId)?.contentsToByteArray() ?:
|
||||||
try {
|
throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
||||||
file.contentsToByteArray()
|
|
||||||
}
|
|
||||||
catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString())
|
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString())
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import org.jetbrains.org.objectweb.asm.util.Printer
|
|||||||
import org.jetbrains.org.objectweb.asm.util.Textifier
|
import org.jetbrains.org.objectweb.asm.util.Textifier
|
||||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
|
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
|
||||||
@@ -65,19 +64,20 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
|||||||
|
|
||||||
const val GENERATE_SMAP = true
|
const val GENERATE_SMAP = true
|
||||||
const val API = Opcodes.ASM5
|
const val API = Opcodes.ASM5
|
||||||
const val THIS = "this"
|
|
||||||
const val THIS_0 = "this$0"
|
|
||||||
const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
|
||||||
const val NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function"
|
const val NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function"
|
||||||
const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
|
||||||
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
|
||||||
const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
|
||||||
const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
|
||||||
const val INLINE_FUN_VAR_SUFFIX = "\$iv"
|
const val INLINE_FUN_VAR_SUFFIX = "\$iv"
|
||||||
const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
|
||||||
|
|
||||||
const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
internal const val THIS = "this"
|
||||||
private const val `RECEIVER$0` = "receiver$0"
|
internal const val THIS_0 = "this$0"
|
||||||
|
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
||||||
|
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
||||||
|
internal const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
||||||
|
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
||||||
|
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
||||||
|
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||||
|
internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||||
|
|
||||||
|
private const val RECEIVER_0 = "receiver$0"
|
||||||
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
||||||
private const val CAPTURED_FIELD_PREFIX = "$"
|
private const val CAPTURED_FIELD_PREFIX = "$"
|
||||||
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
||||||
@@ -88,7 +88,7 @@ private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
|||||||
|
|
||||||
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
||||||
|
|
||||||
fun getMethodNode(
|
internal fun getMethodNode(
|
||||||
classData: ByteArray,
|
classData: ByteArray,
|
||||||
methodName: String,
|
methodName: String,
|
||||||
methodDescriptor: String,
|
methodDescriptor: String,
|
||||||
@@ -143,11 +143,11 @@ fun getMethodNode(
|
|||||||
return SMAPAndMethodNode(node!!, smap)
|
return SMAPAndMethodNode(node!!, smap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findVirtualFile(state: GenerationState, classId: ClassId): VirtualFile? {
|
internal fun findVirtualFile(state: GenerationState, classId: ClassId): VirtualFile? {
|
||||||
return VirtualFileFinder.getInstance(state.project).findVirtualFileWithHeader(classId)
|
return VirtualFileFinder.getInstance(state.project).findVirtualFileWithHeader(classId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findVirtualFileImprecise(state: GenerationState, internalClassName: String): VirtualFile? {
|
internal fun findVirtualFileImprecise(state: GenerationState, internalClassName: String): VirtualFile? {
|
||||||
val packageFqName = JvmClassName.byInternalName(internalClassName).packageFqName
|
val packageFqName = JvmClassName.byInternalName(internalClassName).packageFqName
|
||||||
val classNameWithDollars = internalClassName.substringAfterLast("/", internalClassName)
|
val classNameWithDollars = internalClassName.substringAfterLast("/", internalClassName)
|
||||||
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
|
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
|
||||||
@@ -155,7 +155,7 @@ fun findVirtualFileImprecise(state: GenerationState, internalClassName: String):
|
|||||||
return findVirtualFile(state, ClassId(packageFqName, Name.identifier(classNameWithDollars)))
|
return findVirtualFile(state, ClassId(packageFqName, Name.identifier(classNameWithDollars)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInlineName(
|
internal fun getInlineName(
|
||||||
codegenContext: CodegenContext<*>,
|
codegenContext: CodegenContext<*>,
|
||||||
typeMapper: KotlinTypeMapper,
|
typeMapper: KotlinTypeMapper,
|
||||||
fileClassesManager: JvmFileClassesProvider
|
fileClassesManager: JvmFileClassesProvider
|
||||||
@@ -206,25 +206,25 @@ private fun getInlineName(
|
|||||||
return getInlineName(codegenContext, currentDescriptor.containingDeclaration!!, typeMapper, fileClassesProvider) + "$" + suffix
|
return getInlineName(codegenContext, currentDescriptor.containingDeclaration!!, typeMapper, fileClassesProvider) + "$" + suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInvokeOnLambda(owner: String, name: String): Boolean {
|
internal fun isInvokeOnLambda(owner: String, name: String): Boolean {
|
||||||
return OperatorNameConventions.INVOKE.asString() == name &&
|
return OperatorNameConventions.INVOKE.asString() == name &&
|
||||||
owner.startsWith(NUMBERED_FUNCTION_PREFIX) &&
|
owner.startsWith(NUMBERED_FUNCTION_PREFIX) &&
|
||||||
isInteger(owner.substring(NUMBERED_FUNCTION_PREFIX.length))
|
isInteger(owner.substring(NUMBERED_FUNCTION_PREFIX.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAnonymousConstructorCall(internalName: String, methodName: String): Boolean {
|
internal fun isAnonymousConstructorCall(internalName: String, methodName: String): Boolean {
|
||||||
return "<init>" == methodName && isAnonymousClass(internalName)
|
return "<init>" == methodName && isAnonymousClass(internalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isWhenMappingAccess(internalName: String, fieldName: String): Boolean {
|
internal fun isWhenMappingAccess(internalName: String, fieldName: String): Boolean {
|
||||||
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) && internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX)
|
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) && internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAnonymousSingletonLoad(internalName: String, fieldName: String): Boolean {
|
internal fun isAnonymousSingletonLoad(internalName: String, fieldName: String): Boolean {
|
||||||
return JvmAbi.INSTANCE_FIELD == fieldName && isAnonymousClass(internalName)
|
return JvmAbi.INSTANCE_FIELD == fieldName && isAnonymousClass(internalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAnonymousClass(internalName: String): Boolean {
|
internal fun isAnonymousClass(internalName: String): Boolean {
|
||||||
val shortName = getLastNamePart(internalName)
|
val shortName = getLastNamePart(internalName)
|
||||||
val index = shortName.lastIndexOf("$")
|
val index = shortName.lastIndexOf("$")
|
||||||
|
|
||||||
@@ -246,6 +246,7 @@ fun wrapWithMaxLocalCalc(methodNode: MethodNode): MethodVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isInteger(string: String): Boolean {
|
private fun isInteger(string: String): Boolean {
|
||||||
|
string.toIntOrNull() != null
|
||||||
if (string.isEmpty()) {
|
if (string.isEmpty()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -259,23 +260,23 @@ private fun isInteger(string: String): Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCapturedFieldName(fieldName: String): Boolean {
|
internal fun isCapturedFieldName(fieldName: String): Boolean {
|
||||||
// TODO: improve this heuristic
|
// TODO: improve this heuristic
|
||||||
return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) ||
|
return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) ||
|
||||||
THIS_0 == fieldName ||
|
THIS_0 == fieldName ||
|
||||||
`RECEIVER$0` == fieldName
|
RECEIVER_0 == fieldName
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isReturnOpcode(opcode: Int): Boolean {
|
internal fun isReturnOpcode(opcode: Int): Boolean {
|
||||||
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN
|
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN
|
||||||
}
|
}
|
||||||
|
|
||||||
//marked return could be either non-local or local in case of labeled lambda self-returns
|
//marked return could be either non-local or local in case of labeled lambda self-returns
|
||||||
fun isMarkedReturn(returnIns: AbstractInsnNode): Boolean {
|
internal fun isMarkedReturn(returnIns: AbstractInsnNode): Boolean {
|
||||||
return getMarkedReturnLabelOrNull(returnIns) != null
|
return getMarkedReturnLabelOrNull(returnIns) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMarkedReturnLabelOrNull(returnInsn: AbstractInsnNode): String? {
|
internal fun getMarkedReturnLabelOrNull(returnInsn: AbstractInsnNode): String? {
|
||||||
if (!isReturnOpcode(returnInsn.opcode)) {
|
if (!isReturnOpcode(returnInsn.opcode)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -289,22 +290,22 @@ fun getMarkedReturnLabelOrNull(returnInsn: AbstractInsnNode): String? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateGlobalReturnFlag(iv: InstructionAdapter, labelName: String) {
|
internal fun generateGlobalReturnFlag(iv: InstructionAdapter, labelName: String) {
|
||||||
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false)
|
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getReturnType(opcode: Int): Type {
|
internal fun getReturnType(opcode: Int): Type {
|
||||||
when (opcode) {
|
return when (opcode) {
|
||||||
Opcodes.RETURN -> return Type.VOID_TYPE
|
Opcodes.RETURN -> Type.VOID_TYPE
|
||||||
Opcodes.IRETURN -> return Type.INT_TYPE
|
Opcodes.IRETURN -> Type.INT_TYPE
|
||||||
Opcodes.DRETURN -> return Type.DOUBLE_TYPE
|
Opcodes.DRETURN -> Type.DOUBLE_TYPE
|
||||||
Opcodes.FRETURN -> return Type.FLOAT_TYPE
|
Opcodes.FRETURN -> Type.FLOAT_TYPE
|
||||||
Opcodes.LRETURN -> return Type.LONG_TYPE
|
Opcodes.LRETURN -> Type.LONG_TYPE
|
||||||
else -> return AsmTypes.OBJECT_TYPE
|
else -> AsmTypes.OBJECT_TYPE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun insertNodeBefore(from: MethodNode, to: MethodNode, beforeNode: AbstractInsnNode) {
|
internal fun insertNodeBefore(from: MethodNode, to: MethodNode, beforeNode: AbstractInsnNode) {
|
||||||
val iterator = from.instructions.iterator()
|
val iterator = from.instructions.iterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
val next = iterator.next()
|
val next = iterator.next()
|
||||||
@@ -312,11 +313,11 @@ fun insertNodeBefore(from: MethodNode, to: MethodNode, beforeNode: AbstractInsnN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createEmptyMethodNode(): MethodNode {
|
internal fun createEmptyMethodNode(): MethodNode {
|
||||||
return MethodNode(API, 0, "fake", "()V", null, null)
|
return MethodNode(API, 0, "fake", "()V", null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun firstLabelInChain(node: LabelNode): LabelNode {
|
internal fun firstLabelInChain(node: LabelNode): LabelNode {
|
||||||
var curNode = node
|
var curNode = node
|
||||||
while (curNode.previous is LabelNode) {
|
while (curNode.previous is LabelNode) {
|
||||||
curNode = curNode.previous as LabelNode
|
curNode = curNode.previous as LabelNode
|
||||||
@@ -324,7 +325,7 @@ fun firstLabelInChain(node: LabelNode): LabelNode {
|
|||||||
return curNode
|
return curNode
|
||||||
}
|
}
|
||||||
|
|
||||||
val MethodNode?.nodeText: String
|
internal val MethodNode?.nodeText: String
|
||||||
get() {
|
get() {
|
||||||
if (this == null) {
|
if (this == null) {
|
||||||
return "Not generated"
|
return "Not generated"
|
||||||
@@ -337,7 +338,7 @@ val MethodNode?.nodeText: String
|
|||||||
return name + " " + desc + ":\n" + sw.buffer.toString()
|
return name + " " + desc + ":\n" + sw.buffer.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
val AbstractInsnNode?.insnText: String
|
internal val AbstractInsnNode?.insnText: String
|
||||||
get() {
|
get() {
|
||||||
if (this == null) return "<null>"
|
if (this == null) return "<null>"
|
||||||
val textifier = Textifier()
|
val textifier = Textifier()
|
||||||
@@ -345,75 +346,65 @@ val AbstractInsnNode?.insnText: String
|
|||||||
val sw = StringWriter()
|
val sw = StringWriter()
|
||||||
textifier.print(PrintWriter(sw))
|
textifier.print(PrintWriter(sw))
|
||||||
sw.flush()
|
sw.flush()
|
||||||
return sw.toString().trim { it <= ' ' }
|
return sw.toString().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
val AbstractInsnNode?.insnOpcodeText: String
|
internal val AbstractInsnNode?.insnOpcodeText: String
|
||||||
get() {
|
get() {
|
||||||
return if (this == null) "null" else Printer.OPCODES[opcode]
|
return if (this == null) "null" else Printer.OPCODES[opcode]
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun buildClassReaderByInternalName(state: GenerationState, internalName: String): ClassReader {
|
internal fun buildClassReaderByInternalName(state: GenerationState, internalName: String): ClassReader {
|
||||||
//try to find just compiled classes then in dependencies
|
//try to find just compiled classes then in dependencies
|
||||||
try {
|
val outputFile = state.factory.get(internalName + ".class")
|
||||||
val outputFile = state.factory.get(internalName + ".class")
|
if (outputFile != null) {
|
||||||
if (outputFile != null) {
|
return ClassReader(outputFile.asByteArray())
|
||||||
return ClassReader(outputFile.asByteArray())
|
|
||||||
}
|
|
||||||
val file = findVirtualFileImprecise(state, internalName)
|
|
||||||
if (file != null) {
|
|
||||||
return ClassReader(file.contentsToByteArray())
|
|
||||||
}
|
|
||||||
throw RuntimeException("Couldn't find virtual file for " + internalName)
|
|
||||||
}
|
|
||||||
catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val file = findVirtualFileImprecise(state, internalName) ?:
|
||||||
|
throw RuntimeException("Couldn't find virtual file for " + internalName)
|
||||||
|
|
||||||
|
return ClassReader(file.contentsToByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateFinallyMarker(v: InstructionAdapter, depth: Int, start: Boolean) {
|
internal fun generateFinallyMarker(v: InstructionAdapter, depth: Int, start: Boolean) {
|
||||||
v.iconst(depth)
|
v.iconst(depth)
|
||||||
v.invokestatic(INLINE_MARKER_CLASS_NAME, if (start) INLINE_MARKER_FINALLY_START else INLINE_MARKER_FINALLY_END, "(I)V", false)
|
v.invokestatic(INLINE_MARKER_CLASS_NAME, if (start) INLINE_MARKER_FINALLY_START else INLINE_MARKER_FINALLY_END, "(I)V", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFinallyEnd(node: AbstractInsnNode): Boolean {
|
internal fun isFinallyEnd(node: AbstractInsnNode): Boolean {
|
||||||
return isFinallyMarker(node, INLINE_MARKER_FINALLY_END)
|
return isFinallyMarker(node, INLINE_MARKER_FINALLY_END)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFinallyStart(node: AbstractInsnNode): Boolean {
|
internal fun isFinallyStart(node: AbstractInsnNode): Boolean {
|
||||||
return isFinallyMarker(node, INLINE_MARKER_FINALLY_START)
|
return isFinallyMarker(node, INLINE_MARKER_FINALLY_START)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFinallyMarker(node: AbstractInsnNode?): Boolean {
|
internal fun isFinallyMarker(node: AbstractInsnNode?): Boolean {
|
||||||
return node != null && (isFinallyStart(node) || isFinallyEnd(node))
|
return node != null && (isFinallyStart(node) || isFinallyEnd(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isFinallyMarker(node: AbstractInsnNode, name: String): Boolean {
|
private fun isFinallyMarker(node: AbstractInsnNode, name: String): Boolean {
|
||||||
if (node !is MethodInsnNode) return false
|
if (node !is MethodInsnNode) return false
|
||||||
val method = node
|
return INLINE_MARKER_CLASS_NAME == node.owner && name == node.name
|
||||||
return INLINE_MARKER_CLASS_NAME == method.owner && name == method.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFinallyMarkerRequired(context: MethodContext): Boolean {
|
internal fun isFinallyMarkerRequired(context: MethodContext): Boolean {
|
||||||
return context.isInlineMethodContext || context is InlineLambdaContext
|
return context.isInlineMethodContext || context is InlineLambdaContext
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConstant(ins: AbstractInsnNode): Int {
|
internal fun getConstant(ins: AbstractInsnNode): Int {
|
||||||
val opcode = ins.opcode
|
val opcode = ins.opcode
|
||||||
if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) {
|
return when (opcode) {
|
||||||
return opcode - Opcodes.ICONST_0
|
in Opcodes.ICONST_0..Opcodes.ICONST_5 -> opcode - Opcodes.ICONST_0
|
||||||
}
|
Opcodes.BIPUSH, Opcodes.SIPUSH -> (ins as IntInsnNode).operand
|
||||||
else if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
|
else -> {
|
||||||
return (ins as IntInsnNode).operand
|
(ins as LdcInsnNode).cst as Int
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
val index = ins as LdcInsnNode
|
|
||||||
return index.cst as Int
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeFinallyMarkers(intoNode: MethodNode) {
|
internal fun removeFinallyMarkers(intoNode: MethodNode) {
|
||||||
val instructions = intoNode.instructions
|
val instructions = intoNode.instructions
|
||||||
var curInstr: AbstractInsnNode? = instructions.first
|
var curInstr: AbstractInsnNode? = instructions.first
|
||||||
while (curInstr != null) {
|
while (curInstr != null) {
|
||||||
@@ -430,7 +421,7 @@ fun removeFinallyMarkers(intoNode: MethodNode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
internal fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||||
v.visitMethodInsn(
|
v.visitMethodInsn(
|
||||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||||
if (isStartNotEnd) INLINE_MARKER_BEFORE_METHOD_NAME else INLINE_MARKER_AFTER_METHOD_NAME,
|
if (isStartNotEnd) INLINE_MARKER_BEFORE_METHOD_NAME else INLINE_MARKER_AFTER_METHOD_NAME,
|
||||||
@@ -438,7 +429,7 @@ fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInlineMarker(insn: AbstractInsnNode): Boolean {
|
internal fun isInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, null)
|
return isInlineMarker(insn, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,23 +447,23 @@ private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
|||||||
methodInsnNode.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsnNode.name == INLINE_MARKER_AFTER_METHOD_NAME
|
methodInsnNode.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsnNode.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
internal fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME)
|
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAfterInlineMarker(insn: AbstractInsnNode): Boolean {
|
internal fun isAfterInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME)
|
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLoadStoreArgSize(opcode: Int): Int {
|
internal fun getLoadStoreArgSize(opcode: Int): Int {
|
||||||
return if (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD) 2 else 1
|
return if (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD) 2 else 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isStoreInstruction(opcode: Int): Boolean {
|
internal fun isStoreInstruction(opcode: Int): Boolean {
|
||||||
return opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE
|
return opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calcMarkerShift(parameters: Parameters, node: MethodNode): Int {
|
internal fun calcMarkerShift(parameters: Parameters, node: MethodNode): Int {
|
||||||
val markerShiftTemp = getIndexAfterLastMarker(node)
|
val markerShiftTemp = getIndexAfterLastMarker(node)
|
||||||
return markerShiftTemp - parameters.realParametersSizeOnStack + parameters.argsSizeOnStack
|
return markerShiftTemp - parameters.realParametersSizeOnStack + parameters.argsSizeOnStack
|
||||||
}
|
}
|
||||||
@@ -491,11 +482,11 @@ fun isFakeLocalVariableForInline(name: String): Boolean {
|
|||||||
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) || name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT)
|
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) || name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isThis0(name: String): Boolean {
|
internal fun isThis0(name: String): Boolean {
|
||||||
return THIS_0 == name
|
return THIS_0 == name
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolean {
|
internal fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolean {
|
||||||
val containingDeclaration = functionDescriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
val containingDeclaration = functionDescriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||||
if (containingDeclaration.fqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) {
|
if (containingDeclaration.fqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) {
|
||||||
return false
|
return false
|
||||||
@@ -505,10 +496,12 @@ fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolean {
|
|||||||
}
|
}
|
||||||
val name = functionDescriptor.name.asString()
|
val name = functionDescriptor.name.asString()
|
||||||
val parameters = functionDescriptor.valueParameters
|
val parameters = functionDescriptor.valueParameters
|
||||||
return "enumValues" == name && parameters.size == 0 || "enumValueOf" == name && parameters.size == 1 && KotlinBuiltIns.isString(parameters[0].type)
|
return "enumValues" == name && parameters.size == 0 ||
|
||||||
|
("enumValueOf" == name && parameters.size == 1 &&
|
||||||
|
KotlinBuiltIns.isString(parameters[0].type))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createSpecialEnumMethodBody(
|
internal fun createSpecialEnumMethodBody(
|
||||||
codegen: ExpressionCodegen,
|
codegen: ExpressionCodegen,
|
||||||
name: String,
|
name: String,
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
@@ -535,7 +528,7 @@ fun createSpecialEnumMethodBody(
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String {
|
internal fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String {
|
||||||
return if (isValueOf) Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) else Type.getMethodDescriptor(AsmUtil.getArrayType(type))
|
return if (isValueOf) Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) else Type.getMethodDescriptor(AsmUtil.getArrayType(type))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,10 +546,8 @@ fun FunctionDescriptor.getClassFilePath(typeMapper: KotlinTypeMapper, cache: Inc
|
|||||||
|
|
||||||
return when (source) {
|
return when (source) {
|
||||||
is KotlinJvmBinaryPackageSourceElement -> {
|
is KotlinJvmBinaryPackageSourceElement -> {
|
||||||
val directMember = JvmCodegenUtil.getDirectMember(this)
|
val directMember = JvmCodegenUtil.getDirectMember(this) as? DeserializedCallableMemberDescriptor ?:
|
||||||
if (directMember !is DeserializedCallableMemberDescriptor) {
|
throw AssertionError("Expected DeserializedCallableMemberDescriptor, got: $this")
|
||||||
throw AssertionError("Expected DeserializedCallableMemberDescriptor, got: $this")
|
|
||||||
}
|
|
||||||
val kotlinClass = source.getContainingBinaryClass(directMember) ?:
|
val kotlinClass = source.getContainingBinaryClass(directMember) ?:
|
||||||
throw AssertionError("Descriptor $this is not found, in: $source")
|
throw AssertionError("Descriptor $this is not found, in: $source")
|
||||||
if (kotlinClass !is VirtualFileKotlinClass) {
|
if (kotlinClass !is VirtualFileKotlinClass) {
|
||||||
@@ -580,7 +571,7 @@ fun FunctionDescriptor.getClassFilePath(typeMapper: KotlinTypeMapper, cache: Inc
|
|||||||
|
|
||||||
class InlineOnlySmapSkipper(codegen: ExpressionCodegen) {
|
class InlineOnlySmapSkipper(codegen: ExpressionCodegen) {
|
||||||
|
|
||||||
val callLineNumber = codegen.lastLineNumber
|
private val callLineNumber = codegen.lastLineNumber
|
||||||
|
|
||||||
fun markCallSiteLineNumber(mv: MethodVisitor) {
|
fun markCallSiteLineNumber(mv: MethodVisitor) {
|
||||||
if (callLineNumber >= 0) {
|
if (callLineNumber >= 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user