diff --git a/.idea/dictionaries/dzharkov.xml b/.idea/dictionaries/dzharkov.xml
new file mode 100644
index 00000000000..fb88a11d30d
--- /dev/null
+++ b/.idea/dictionaries/dzharkov.xml
@@ -0,0 +1,7 @@
+
+
+
+ insn
+
+
+
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
index 3dfea9116ff..64c3e569a4d 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
@@ -2780,7 +2780,7 @@ public class ExpressionCodegen extends KtVisitor impleme
"Non-reified type parameter under ::class should be rejected by type checker: " + typeParameterDescriptor;
assert codegen != null :
"Reference to member of reified type should be rejected by type checker " + typeParameterDescriptor;
- codegen.putReifierMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME);
+ codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
}
putJavaLangClassInstance(v, classAsmType);
@@ -3394,9 +3394,9 @@ public class ExpressionCodegen extends KtVisitor impleme
public void newArrayInstruction(@NotNull KotlinType arrayType) {
if (KotlinBuiltIns.isArray(arrayType)) {
KotlinType elementJetType = arrayType.getArguments().get(0).getType();
- putReifierMarkerIfTypeIsReifiedParameter(
+ putReifiedOperationMarkerIfTypeIsReifiedParameter(
elementJetType,
- ReifiedTypeInliner.NEW_ARRAY_MARKER_METHOD_NAME
+ ReifiedTypeInliner.OperationKind.NEW_ARRAY
);
v.newarray(boxType(asmType(elementJetType)));
}
@@ -3753,32 +3753,35 @@ The "returned" value of try expression with no finally is either the last expres
private void generateInstanceOfInstruction(@NotNull KotlinType jetType) {
Type type = boxType(asmType(jetType));
- putReifierMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.INSTANCEOF_MARKER_METHOD_NAME);
+ putReifiedOperationMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.OperationKind.INSTANCEOF);
TypeIntrinsics.instanceOf(v, jetType, type);
}
@NotNull
private StackValue generateCheckCastInstruction(@NotNull KotlinType jetType, boolean safeAs) {
Type type = boxType(asmType(jetType));
- putReifierMarkerIfTypeIsReifiedParameter(jetType,
- safeAs ? ReifiedTypeInliner.SAFE_CHECKCAST_MARKER_METHOD_NAME
- : ReifiedTypeInliner.CHECKCAST_MARKER_METHOD_NAME);
+ putReifiedOperationMarkerIfTypeIsReifiedParameter(jetType,
+ safeAs ? ReifiedTypeInliner.OperationKind.SAFE_CHECKCAST
+ : ReifiedTypeInliner.OperationKind.CHECKCAST);
TypeIntrinsics.checkcast(v, jetType, type, safeAs);
return StackValue.onStack(type);
}
- public void putReifierMarkerIfTypeIsReifiedParameter(@NotNull KotlinType type, @NotNull String markerMethodName) {
+ public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
+ @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind
+ ) {
TypeParameterDescriptor typeParameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
if (typeParameterDescriptor != null && typeParameterDescriptor.isReified()) {
if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
parentCodegen.getReifiedTypeParametersUsages().
addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
}
- boolean putNullableFlag = ReifiedTypeInliner.isNullableMarkerInstruction(markerMethodName) && type.isMarkedNullable();
+ v.iconst(operationKind.getId());
+ boolean putNullableFlag = operationKind.isTypeNullabilityAware() && type.isMarkedNullable();
v.visitLdcInsn(typeParameterDescriptor.getName().asString() + (putNullableFlag ? "?" : ""));
v.invokestatic(
- IntrinsicMethods.INTRINSICS_CLASS_NAME, markerMethodName,
- Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false
+ IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.REIFIED_OPERATION_MARKER_METHOD_NAME,
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class)), false
);
}
}
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 859eabe13ca..806fa291e4e 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt
@@ -16,12 +16,12 @@
package org.jetbrains.kotlin.codegen.inline
-import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.generateIsCheck
import org.jetbrains.kotlin.codegen.generateNullCheckForNonSafeAs
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
+import org.jetbrains.kotlin.codegen.optimization.common.intConstant
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -36,22 +36,21 @@ private class ParameterNameAndNullability(val name: String, val nullable: Boolea
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
+ enum class OperationKind {
+ NEW_ARRAY, CHECKCAST, SAFE_CHECKCAST, INSTANCEOF, JAVA_CLASS;
+
+ val id: Int get() = ordinal
+ val isTypeNullabilityAware: Boolean get() = this == CHECKCAST || this == INSTANCEOF
+ }
+
companion object {
- public val NEW_ARRAY_MARKER_METHOD_NAME: String = "reifyNewArray"
- public val CHECKCAST_MARKER_METHOD_NAME: String = "reifyCheckcast"
- public val SAFE_CHECKCAST_MARKER_METHOD_NAME: String = "reifySafeCheckcast"
- public val INSTANCEOF_MARKER_METHOD_NAME: String = "reifyInstanceof"
- public val JAVA_CLASS_MARKER_METHOD_NAME: String = "reifyJavaClass"
- public val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME: String = "needClassReification"
+ @JvmField
+ public val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker"
+ @JvmField
+ public val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
- private val PARAMETRISED_MARKERS = ImmutableSet.of(
- NEW_ARRAY_MARKER_METHOD_NAME,
- CHECKCAST_MARKER_METHOD_NAME, SAFE_CHECKCAST_MARKER_METHOD_NAME,
- INSTANCEOF_MARKER_METHOD_NAME, JAVA_CLASS_MARKER_METHOD_NAME
- )
-
- private fun isParametrisedReifiedMarker(insn: AbstractInsnNode) =
- isReifiedMarker(insn) { PARAMETRISED_MARKERS.contains(it) }
+ private fun isOperationReifiedMarker(insn: AbstractInsnNode) =
+ isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
private fun isReifiedMarker(insn: AbstractInsnNode, namePredicate: (String) -> Boolean): Boolean {
if (insn.getOpcode() != Opcodes.INVOKESTATIC || insn !is MethodInsnNode) return false
@@ -70,10 +69,6 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
Type.getMethodDescriptor(Type.VOID_TYPE), false
);
}
-
- @JvmStatic
- public fun isNullableMarkerInstruction(marker: String) = INSTANCEOF_MARKER_METHOD_NAME == marker ||
- CHECKCAST_MARKER_METHOD_NAME == marker
}
private var maxStackSize = 0
@@ -89,7 +84,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
maxStackSize = 0
var result = ReifiedTypeParametersUsages()
for (insn in instructions.toArray()) {
- if (isParametrisedReifiedMarker(insn)) {
+ if (isOperationReifiedMarker(insn)) {
val newName: String? = processReifyMarker(insn as MethodInsnNode, instructions)
if (newName != null) {
result.addUsedReifiedParameter(newName)
@@ -142,10 +137,11 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
* or null if it shouldn't
*/
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): String? {
- val parameter = getParameter(insn) ?: return null
+ val operationKind = insn.operationKind ?: return null
+ val parameter = insn.parameterNameAndNullability ?: return null
val mapping = parametersMapping?.get(parameter.name) ?: return null
val kotlinType =
- if (isNullableMarkerInstruction(insn.name) && parameter.nullable)
+ if (operationKind.isTypeNullabilityAware && parameter.nullable)
TypeUtils.makeNullable(mapping.type)
else
mapping.type
@@ -156,21 +152,21 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
// process* methods return false if marker should be reified further
// or it's invalid (may be emitted explicitly in code)
// they return true if instruction is reified and marker can be deleted
- if (when (insn.name) {
- NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType)
- CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, kotlinType, asmType, safe = false)
- SAFE_CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, kotlinType, asmType, safe = true)
- INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, instructions, kotlinType, asmType)
- JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType)
- else -> false
+ if (when (operationKind) {
+ OperationKind.NEW_ARRAY -> processNewArray(insn, asmType)
+ OperationKind.CHECKCAST -> processCheckcast(insn, instructions, kotlinType, asmType, safe = false)
+ OperationKind.SAFE_CHECKCAST -> processCheckcast(insn, instructions, kotlinType, asmType, safe = true)
+ OperationKind.INSTANCEOF -> processInstanceof(insn, instructions, kotlinType, asmType)
+ OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
}) {
- instructions.remove(insn.getPrevious()!!)
- instructions.remove(insn)
+ instructions.remove(insn.previous.previous!!) // PUSH operation ID
+ instructions.remove(insn.previous!!) // PUSH type parameter
+ instructions.remove(insn) // INVOKESTATIC marker method
}
return null
} else {
- val nullableSuffix = if (isNullableMarkerInstruction(insn.name) && kotlinType.isMarkedNullable) "?" else ""
+ val nullableSuffix = if (operationKind.isTypeNullabilityAware && kotlinType.isMarkedNullable) "?" else ""
instructions.set(insn.previous!!, LdcInsnNode(mapping.newName + nullableSuffix))
return mapping.newName
}
@@ -187,7 +183,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { instanceofInsn: AbstractInsnNode ->
if (instanceofInsn !is TypeInsnNode) return false
- addNullCheckForAsIfNeeded(insn.previous!!, instructions, jetType, safe)
+ addNullCheckForAsIfNeeded(insn.previous.previous, instructions, jetType, safe)
TypeIntrinsics.checkcast(instanceofInsn, instructions, jetType, asmType, safe)
return true
}
@@ -214,7 +210,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
private fun addNullCheckForIsIfNeeded(insn: AbstractInsnNode, instructions: InsnList, type: KotlinType) {
if (TypeUtils.isNullableType(type)) {
val instanceOf = insn.next
- insertNullCheckAround(instructions, insn.previous!!, instanceOf)
+ insertNullCheckAround(instructions, insn.previous.previous, instanceOf)
maxStackSize = Math.max(maxStackSize, 2)
}
}
@@ -262,10 +258,13 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
return true
}
- private fun getParameter(insn: MethodInsnNode): ParameterNameAndNullability? {
- val prev = insn.getPrevious()!!
+}
- val parameterNameWithFlag = when (prev.getOpcode()) {
+private val MethodInsnNode.parameterNameAndNullability: ParameterNameAndNullability?
+ get() {
+ val prev = previous!!
+
+ val parameterNameWithFlag = when (prev.opcode) {
Opcodes.LDC -> (prev as LdcInsnNode).cst as String
else -> return null
}
@@ -273,7 +272,11 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
val parameterName = if (parameterNameWithFlag.endsWith("?")) parameterNameWithFlag.dropLast(1) else parameterNameWithFlag
return ParameterNameAndNullability(parameterName, parameterName !== parameterNameWithFlag)
}
-}
+
+private val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? get() =
+ previous?.previous?.intConstant?.let {
+ ReifiedTypeInliner.OperationKind.values().getOrNull(it)
+ }
public class ReifiedTypeParameterMappings() {
private val mappingsByName = hashMapOf()
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassFunction.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassFunction.kt
index 10c21651fcc..6bb067cf8d8 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassFunction.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/JavaClassFunction.kt
@@ -30,7 +30,7 @@ public class JavaClassFunction : IntrinsicMethod() {
val javaClass = resolvedCall.getResultingDescriptor().getReturnType()!!.getArguments().first().getType()
return object : IntrinsicCallable(getType(javaClass>()), listOf(), null, null) {
override fun invokeIntrinsic(v: InstructionAdapter) {
- codegen.putReifierMarkerIfTypeIsReifiedParameter(javaClass, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME)
+ codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(javaClass, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
putJavaLangClassInstance(v, codegen.getState().typeMapper.mapType(javaClass))
}
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt
index aeac767d3a0..3a00838e5ea 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaProperty.kt
@@ -39,7 +39,7 @@ public class KClassJavaProperty : IntrinsicPropertyGetter() {
return when {
isReifiedTypeParameter(type) -> {
StackValue.operation(returnType) { iv ->
- codegen.putReifierMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME)
+ codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
AsmUtil.putJavaLangClassInstance(iv, asmType)
coerceToJavaLangClass(iv, returnType)
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
index 62679d28c1b..29ab5499a5e 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
@@ -16,9 +16,8 @@
package org.jetbrains.kotlin.codegen.optimization.common
-import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
-import org.jetbrains.org.objectweb.asm.tree.InsnList
-import org.jetbrains.org.objectweb.asm.tree.MethodNode
+import org.jetbrains.org.objectweb.asm.Opcodes.*
+import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
val AbstractInsnNode.isMeaningful: Boolean get() =
@@ -97,3 +96,24 @@ inline fun AbstractInsnNode.findPreviousOrNull(predicate: (AbstractInsnNode) ->
fun AbstractInsnNode.hasOpcode(): Boolean =
getOpcode() >= 0
+
+// See InstructionAdapter
+//
+// public void iconst(final int cst) {
+// if (cst >= -1 && cst <= 5) {
+// mv.visitInsn(Opcodes.ICONST_0 + cst);
+// } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
+// mv.visitIntInsn(Opcodes.BIPUSH, cst);
+// } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
+// mv.visitIntInsn(Opcodes.SIPUSH, cst);
+// } else {
+// mv.visitLdcInsn(new Integer(cst));
+// }
+// }
+val AbstractInsnNode.intConstant: Int? get() =
+ when (opcode) {
+ in ICONST_M1..ICONST_5 -> opcode - ICONST_0
+ BIPUSH, SIPUSH -> (this as IntInsnNode).operand
+ LDC -> (this as LdcInsnNode).cst as? Int
+ else -> null
+ }
diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java
index 0a2efcb5fa4..b0af8e612a3 100644
--- a/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java
+++ b/core/runtime.jvm/src/kotlin/jvm/internal/Intrinsics.java
@@ -173,35 +173,11 @@ public class Intrinsics {
throw new UnsupportedOperationException(message);
}
- public static void reifyNewArray(String typeParameterIdentifier) {
+ public static void reifiedOperationMarker(int id, String typeParameterIdentifier) {
throwUndefinedForReified();
}
- public static void reifyNewArray(String typeParameterIdentifier, String message) {
- throwUndefinedForReified(message);
- }
-
- public static void reifyCheckcast(String typeParameterIdentifier) {
- throwUndefinedForReified();
- }
-
- public static void reifyCheckcast(String typeParameterIdentifier, String message) {
- throwUndefinedForReified(message);
- }
-
- public static void reifyInstanceof(String typeParameterIdentifier) {
- throwUndefinedForReified();
- }
-
- public static void reifyInstanceof(String typeParameterIdentifier, String message) {
- throwUndefinedForReified(message);
- }
-
- public static void reifyJavaClass(String typeParameterIdentifier) {
- throwUndefinedForReified();
- }
-
- public static void reifyJavaClass(String typeParameterIdentifier, String message) {
+ public static void reifiedOperationMarker(int id, String typeParameterIdentifier, String message) {
throwUndefinedForReified(message);
}