From d12e5ddafc7a705efcabbf6fc24ec5184ace4743 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 22 Nov 2018 16:18:49 +0100 Subject: [PATCH] Generate bytecode for array intrinsics manually #KT-28285 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 7 +- .../kotlin/codegen/inline/InlineCodegen.kt | 19 +- .../codegen/inline/ReifiedTypeInliner.kt | 11 + .../codegen/inline/inlineCodegenUtils.kt | 7 - .../intrinsics/IntrinsicArrayConstructors.kt | 190 ++++++++++-------- compiler/compiler.pro | 2 - compiler/compiler.pro.181 | 2 - compiler/compiler.pro.191 | 2 - compiler/compiler.pro.as32 | 2 - compiler/compiler.pro.as34 | 2 - .../kotlin/resolve/jvm/AsmTypes.java | 2 + 11 files changed, 128 insertions(+), 118 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 6c5bfa11e8c..0f6d68f9124 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4834,12 +4834,7 @@ The "returned" value of try expression with no finally is either the last expres if (codegen != null) { codegen.consumeReifiedOperationMarker(typeParameterDescriptor); } - v.iconst(operationKind.getId()); - v.visitLdcInsn(typeParameterAndReificationArgument.getSecond().asString()); - v.invokestatic( - IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.REIFIED_OPERATION_MARKER_METHOD_NAME, - Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class)), false - ); + ReifiedTypeInliner.putReifiedOperationMarker(operationKind, typeParameterAndReificationArgument.getSecond(), v); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 1e3275b8ae9..4b05789cd34 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -7,13 +7,12 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import com.intellij.util.ArrayUtil -import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive import org.jetbrains.kotlin.codegen.context.ClosureContext -import org.jetbrains.kotlin.codegen.intrinsics.bytecode -import org.jetbrains.kotlin.codegen.intrinsics.classId +import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.isReleaseCoroutines @@ -520,9 +519,13 @@ abstract class InlineCodegen( asmMethod: Method ): SMAPAndMethodNode? { if (isBuiltInArrayIntrinsic(callableDescriptor)) { - val classId = classId - val bytes = state.inlineCache.classBytes.getOrPut(classId) { bytecode } - return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, AsmUtil.asmTypeByClassId(classId)) + val body = when { + callableDescriptor is FictitiousArrayConstructor -> IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod) + callableDescriptor.name.asString() == "emptyArray" -> IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod) + callableDescriptor.name.asString() == "arrayOf" -> IntrinsicArrayConstructors.generateArrayOfBody(asmMethod) + else -> throw UnsupportedOperationException("Not an array intrinsic: $callableDescriptor") + } + return SMAPAndMethodNode(body, SMAP(listOf(FileMapping.SKIP))) } assert(callableDescriptor is DeserializedCallableMemberDescriptor) { "Not a deserialized function or proper: " + callableDescriptor } @@ -552,7 +555,9 @@ abstract class InlineCodegen( private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean { if (callableDescriptor is FictitiousArrayConstructor) return true val name = callableDescriptor.name.asString() - return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration is BuiltInsPackageFragment + return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration.let { container -> + container is PackageFragmentDescriptor && container.fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME + } } /*descriptor is null for captured vars*/ diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 93095b6484d..18626791afa 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.intConstant import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.Variance @@ -96,6 +97,16 @@ class ReifiedTypeInliner( Type.getMethodDescriptor(Type.VOID_TYPE), false ) } + + @JvmStatic + fun putReifiedOperationMarker(operationKind: OperationKind, argument: ReificationArgument, v: InstructionAdapter) { + v.iconst(operationKind.id) + v.visitLdcInsn(argument.asString()) + v.invokestatic( + IntrinsicMethods.INTRINSICS_CLASS_NAME, REIFIED_OPERATION_MARKER_METHOD_NAME, + Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, AsmTypes.JAVA_STRING_TYPE), false + ) + } } private var maxStackSize = 0 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index a4e63e95a73..fccf3d71787 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.codegen.context.CodegenContextUtil import org.jetbrains.kotlin.codegen.context.InlineLambdaContext import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction -import org.jetbrains.kotlin.codegen.intrinsics.classId import org.jetbrains.kotlin.codegen.optimization.common.intConstant import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -75,7 +74,6 @@ private const val INLINE_MARKER_RETURNS_UNIT = 2 private const val INLINE_MARKER_FAKE_CONTINUATION = 3 private const val INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL = 4 private const val INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL = 5 -private val INTRINSIC_ARRAY_CONSTRUCTOR_TYPE = AsmUtil.asmTypeByClassId(classId) internal fun getMethodNode( classData: ByteArray, @@ -135,11 +133,6 @@ internal fun getMethodNode( return null } - if (INTRINSIC_ARRAY_CONSTRUCTOR_TYPE == classType) { - // Don't load source map for intrinsic array constructors - debugInfo[0] = null - } - val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classType.internalName, lines[0], lines[1]) return SMAPAndMethodNode(node!!, smap) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt index e1bed856f27..f1fbc775d52 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt @@ -14,98 +14,112 @@ * limitations under the License. */ -@file:Suppress("unused", "UNCHECKED_CAST") - package org.jetbrains.kotlin.codegen.intrinsics -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.inline.ReificationArgument +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.commons.Method +import org.jetbrains.org.objectweb.asm.tree.MethodNode -// Bodies of methods in this file are used in InlineCodegen to inline array constructors. It is loaded via reflection at runtime. -// TODO: generate the bytecode manually instead, do not depend on the previous compiler working correctly here +internal object IntrinsicArrayConstructors { + fun generateArrayConstructorBody(method: Method): MethodNode { + val node = MethodNode( + Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null + ) -internal val classId: ClassId = - ClassId.topLevel(FqName("org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt")) + val arrayType = method.returnType + val elementType = AsmUtil.correctElementType(arrayType) -internal val bytecode: ByteArray by lazy { - val stream = object {}::class.java.classLoader.getResourceAsStream("${classId.asString()}.class") - stream.readBytes().apply { - stream.close() + val size = StackValue.local(0, Type.INT_TYPE) + val lambda = StackValue.local(1, AsmTypes.FUNCTION1) + val loopIndex = StackValue.local(2, Type.INT_TYPE) + val array = StackValue.local(3, arrayType) + + /* + inline fun Array(size: Int, init: (Int) -> T): Array { + val result = arrayOfNulls(size) + for (i in 0 until size) { + result[i] = init(i) + } + return result as Array + } + */ + + val iv = InstructionAdapter(node) + size.put(iv) + if (elementType.sort == Type.OBJECT) { + ReifiedTypeInliner.putReifiedOperationMarker(ReifiedTypeInliner.OperationKind.NEW_ARRAY, ReificationArgument("T", true, 0), iv) + } + iv.newarray(elementType) + array.store(StackValue.onStack(arrayType), iv) + loopIndex.store(StackValue.constant(0), iv) + val begin = Label() + iv.visitLabel(begin) + loopIndex.put(iv) + size.put(iv) + val end = Label() + iv.ificmpge(end) + array.put(iv) + loopIndex.put(iv) + lambda.put(iv) + loopIndex.put(AsmUtil.boxType(Type.INT_TYPE), iv) + iv.invokeinterface( + AsmTypes.FUNCTION1.internalName, OperatorNameConventions.INVOKE.asString(), + Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE) + ) + StackValue.coerce(AsmTypes.OBJECT_TYPE, elementType, iv) + iv.astore(elementType) + iv.iinc(loopIndex.index, 1) + iv.goTo(begin) + iv.visitLabel(end) + array.put(iv) + iv.areturn(arrayType) + iv.visitMaxs(5, 4) + + return node + } + + fun generateEmptyArrayBody(method: Method): MethodNode { + val node = MethodNode( + Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null + ) + + /* + inline fun emptyArray(): Array = arrayOfNulls(0) as Array + */ + + val iv = InstructionAdapter(node) + iv.iconst(0) + ReifiedTypeInliner.putReifiedOperationMarker(ReifiedTypeInliner.OperationKind.NEW_ARRAY, ReificationArgument("T", true, 0), iv) + iv.newarray(AsmTypes.OBJECT_TYPE) + iv.areturn(AsmTypes.OBJECT_TYPE) + iv.visitMaxs(3, 1) + + return node + } + + fun generateArrayOfBody(method: Method): MethodNode { + val node = MethodNode( + Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null + ) + + /* + inline fun arrayOf(vararg elements: T): Array = elements as Array + */ + + val iv = InstructionAdapter(node) + iv.load(0, AsmTypes.OBJECT_TYPE) + iv.areturn(AsmTypes.OBJECT_TYPE) + iv.visitMaxs(1, 1) + + return node } } - -private inline fun emptyArray(): Array = arrayOfNulls(0) as Array - -private inline fun arrayOf(vararg elements: T): Array = elements as Array - -private inline fun Array(size: Int, init: (Int) -> T): Array { - val result = arrayOfNulls(size) - for (i in result.indices) { - result[i] = init(i) - } - return result as Array -} - -private inline fun DoubleArray(size: Int, init: (Int) -> Double): DoubleArray { - val result = DoubleArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun FloatArray(size: Int, init: (Int) -> Float): FloatArray { - val result = FloatArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun LongArray(size: Int, init: (Int) -> Long): LongArray { - val result = LongArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun IntArray(size: Int, init: (Int) -> Int): IntArray { - val result = IntArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun CharArray(size: Int, init: (Int) -> Char): CharArray { - val result = CharArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun ShortArray(size: Int, init: (Int) -> Short): ShortArray { - val result = ShortArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun ByteArray(size: Int, init: (Int) -> Byte): ByteArray { - val result = ByteArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} - -private inline fun BooleanArray(size: Int, init: (Int) -> Boolean): BooleanArray { - val result = BooleanArray(size) - for (i in result.indices) { - result[i] = init(i) - } - return result -} diff --git a/compiler/compiler.pro b/compiler/compiler.pro index b168a471463..765db257657 100644 --- a/compiler/compiler.pro +++ b/compiler/compiler.pro @@ -115,8 +115,6 @@ messages/**) -keep class org.jetbrains.kotlin.container.** { *; } --keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } - -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/compiler.pro.181 b/compiler/compiler.pro.181 index 51b5aa0ccc1..eeca2ef8bf0 100644 --- a/compiler/compiler.pro.181 +++ b/compiler/compiler.pro.181 @@ -100,8 +100,6 @@ messages/**) -keep class org.jetbrains.kotlin.container.** { *; } --keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } - -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/compiler.pro.191 b/compiler/compiler.pro.191 index 6cac2e1c540..c8589f42d1d 100644 --- a/compiler/compiler.pro.191 +++ b/compiler/compiler.pro.191 @@ -116,8 +116,6 @@ messages/**) -keep class org.jetbrains.kotlin.container.** { *; } --keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } - -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/compiler.pro.as32 b/compiler/compiler.pro.as32 index 0cc79a79ec8..50ff3212f55 100644 --- a/compiler/compiler.pro.as32 +++ b/compiler/compiler.pro.as32 @@ -101,8 +101,6 @@ messages/**) -keep class org.jetbrains.kotlin.container.** { *; } --keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } - -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/compiler.pro.as34 b/compiler/compiler.pro.as34 index 6cac2e1c540..c8589f42d1d 100644 --- a/compiler/compiler.pro.as34 +++ b/compiler/compiler.pro.as34 @@ -116,8 +116,6 @@ messages/**) -keep class org.jetbrains.kotlin.container.** { *; } --keep class org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt { *; } - -keep class org.jetbrains.org.objectweb.asm.Opcodes { *; } -keep class org.jetbrains.kotlin.codegen.extensions.** { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 4bf5a8f82f0..24c67c34656 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -38,6 +38,8 @@ public class AsmTypes { public static final Type RESULT_FAILURE = Type.getObjectType("kotlin/Result$Failure"); + public static final Type FUNCTION1 = Type.getObjectType("kotlin/jvm/functions/Function1"); + public static final Type[] PROPERTY_REFERENCE_IMPL = { Type.getObjectType("kotlin/jvm/internal/PropertyReference0Impl"), Type.getObjectType("kotlin/jvm/internal/PropertyReference1Impl"),