Support generic array creation for reified inlined
This commit is contained in:
committed by
Andrey Breslav
parent
060c30746f
commit
4a66ab3627
@@ -30,9 +30,7 @@ import org.jetbrains.jet.backend.common.CodegenUtil;
|
||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.context.*;
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegen;
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.inline.NameGenerator;
|
||||
import org.jetbrains.jet.codegen.inline.*;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
@@ -2186,8 +2184,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
|
||||
}
|
||||
|
||||
CallGenerator callGenerator = getOrCreateCallGenerator(resolvedCall);
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
CallGenerator callGenerator = getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement());
|
||||
|
||||
assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
|
||||
"Tail recursive method can't be inlined: " + descriptor;
|
||||
@@ -2230,7 +2228,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected CallGenerator getOrCreateCallGenerator(@NotNull CallableDescriptor descriptor, @Nullable JetElement callElement) {
|
||||
protected CallGenerator getOrCreateCallGenerator(
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@Nullable JetElement callElement,
|
||||
@Nullable ReifiedTypeParameterMappings reifierTypeParameterMappings
|
||||
) {
|
||||
if (callElement == null) return defaultCallGenerator;
|
||||
|
||||
boolean isInline = state.isInlineEnabled() &&
|
||||
@@ -2240,7 +2242,43 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
if (!isInline) return defaultCallGenerator;
|
||||
|
||||
SimpleFunctionDescriptor original = DescriptorUtils.unwrapFakeOverride((SimpleFunctionDescriptor) descriptor.getOriginal());
|
||||
return new InlineCodegen(this, state, original, callElement);
|
||||
return new InlineCodegen(this, state, original, callElement, reifierTypeParameterMappings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallGenerator getOrCreateCallGenerator(@NotNull FunctionDescriptor descriptor, @Nullable JetNamedFunction function) {
|
||||
return getOrCreateCallGenerator(descriptor, function, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
|
||||
ReifiedTypeParameterMappings mappings = new ReifiedTypeParameterMappings(typeArguments.size());
|
||||
for (Map.Entry<TypeParameterDescriptor, JetType> entry : typeArguments.entrySet()) {
|
||||
TypeParameterDescriptor key = entry.getKey();
|
||||
if (!key.isReified()) continue;
|
||||
|
||||
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(entry.getValue());
|
||||
if (parameterDescriptor == null) {
|
||||
// type is not generic
|
||||
// boxType call needed because inlined method is compiled for T as java/lang/Object
|
||||
mappings.addParameterMappingToType(
|
||||
key.getIndex(),
|
||||
key.getName().getIdentifier(),
|
||||
boxType(asmType(entry.getValue()))
|
||||
);
|
||||
}
|
||||
else {
|
||||
mappings.addParameterMappingToNewParameter(
|
||||
key.getIndex(),
|
||||
key.getName().getIdentifier(),
|
||||
parameterDescriptor.getIndex()
|
||||
);
|
||||
}
|
||||
}
|
||||
return getOrCreateCallGenerator(
|
||||
resolvedCall.getResultingDescriptor(), resolvedCall.getCall().getCallElement(), mappings
|
||||
);
|
||||
}
|
||||
|
||||
public void generateReceiverValue(@NotNull ReceiverValue receiverValue, @NotNull Type type) {
|
||||
@@ -3373,6 +3411,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
if (isArray) {
|
||||
gen(args.get(0), Type.INT_TYPE);
|
||||
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(
|
||||
arrayType.getArguments().get(0).getType()
|
||||
);
|
||||
if (parameterDescriptor != null && parameterDescriptor.isReified()) {
|
||||
v.iconst(parameterDescriptor.getIndex());
|
||||
v.invokestatic(
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.NEW_ARRAY_MARKER_METHOD_NAME,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false
|
||||
);
|
||||
}
|
||||
v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -76,13 +76,16 @@ public class InlineCodegen implements CallGenerator {
|
||||
protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
|
||||
protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
|
||||
|
||||
private final ReifiedTypeInliner reifiedTypeInliner;
|
||||
|
||||
private LambdaInfo activeLambda;
|
||||
|
||||
public InlineCodegen(
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull GenerationState state,
|
||||
@NotNull SimpleFunctionDescriptor functionDescriptor,
|
||||
@NotNull JetElement callElement
|
||||
@NotNull JetElement callElement,
|
||||
@Nullable ReifiedTypeParameterMappings typeParameterMappings
|
||||
) {
|
||||
assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor;
|
||||
|
||||
@@ -91,6 +94,9 @@ public class InlineCodegen implements CallGenerator {
|
||||
this.codegen = codegen;
|
||||
this.callElement = callElement;
|
||||
this.functionDescriptor = functionDescriptor.getOriginal();
|
||||
|
||||
reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
|
||||
|
||||
initialFrameSize = codegen.getFrameMap().getCurrentSize();
|
||||
|
||||
context = (MethodContext) getContext(functionDescriptor, state);
|
||||
@@ -200,6 +206,7 @@ public class InlineCodegen implements CallGenerator {
|
||||
}
|
||||
|
||||
private InlineResult inlineCall(MethodNode node) {
|
||||
reifiedTypeInliner.reifyInstructions(node.instructions);
|
||||
generateClosuresBodies();
|
||||
|
||||
//through generation captured parameters will be added to invocationParamBuilder
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.IntInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods
|
||||
import kotlin.platform.platformStatic
|
||||
import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode
|
||||
import java.util.ArrayList
|
||||
|
||||
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
|
||||
|
||||
class object {
|
||||
public val NEW_ARRAY_MARKER_METHOD_NAME: String = "reifyNewArray"
|
||||
}
|
||||
|
||||
public fun reifyInstructions(instructions: InsnList) {
|
||||
if (parametersMapping == null) return
|
||||
for (insn in instructions.toArray()) {
|
||||
if (isReifiedMarker(insn)) {
|
||||
processReifyMarker(insn as MethodInsnNode, instructions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isReifiedMarker(insn: AbstractInsnNode): Boolean {
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC || insn !is MethodInsnNode) return false
|
||||
return insn.owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && insn.name.startsWith("reify")
|
||||
}
|
||||
|
||||
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList) {
|
||||
val mapping = getTypeParameterMapping(insn) ?: return
|
||||
|
||||
if (mapping.asmType != null) {
|
||||
if (!when (insn.name) {
|
||||
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, mapping.asmType)
|
||||
else -> false
|
||||
}) {
|
||||
return
|
||||
}
|
||||
instructions.remove(insn.getPrevious()!!)
|
||||
instructions.remove(insn)
|
||||
} else {
|
||||
instructions.set(insn.getPrevious()!!, iconstInsn(mapping.newIndex!!))
|
||||
}
|
||||
}
|
||||
|
||||
private fun processNewArray(insn: MethodInsnNode, parameter: Type): Boolean {
|
||||
if (insn.getNext()?.getOpcode() != Opcodes.ANEWARRAY) return false
|
||||
val next = insn.getNext() as TypeInsnNode
|
||||
next.desc = parameter.getInternalName()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getParameterIndex(insn: MethodInsnNode): Int? {
|
||||
val prev = insn.getPrevious()!!
|
||||
|
||||
return when (prev.getOpcode()) {
|
||||
Opcodes.ICONST_0 -> 0
|
||||
Opcodes.ICONST_1 -> 1
|
||||
Opcodes.ICONST_2 -> 2
|
||||
Opcodes.ICONST_3 -> 3
|
||||
Opcodes.ICONST_4 -> 4
|
||||
Opcodes.ICONST_5 -> 5
|
||||
Opcodes.BIPUSH, Opcodes.SIPUSH -> (prev as IntInsnNode).operand
|
||||
Opcodes.LDC -> (prev as LdcInsnNode).cst as Int
|
||||
else -> throw AssertionError("Unexpected opcode ${prev.getOpcode()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTypeParameterMapping(insn: MethodInsnNode): ReifiedTypeParameterMapping? {
|
||||
return parametersMapping?.get(getParameterIndex(insn) ?: return null)
|
||||
}
|
||||
}
|
||||
|
||||
public class ReifiedTypeParameterMappings(private val size: Int) {
|
||||
private val mappingsByIndex = arrayOfNulls<ReifiedTypeParameterMapping>(size)
|
||||
private val indexByParameterName = hashMapOf<String, Int>()
|
||||
|
||||
public fun addParameterMappingToType(index: Int, name: String, asmType: Type) {
|
||||
mappingsByIndex[index] = ReifiedTypeParameterMapping(name, asmType, null)
|
||||
indexByParameterName[name] = index
|
||||
}
|
||||
|
||||
public fun addParameterMappingToNewParameter(index: Int, name: String, newIndex: Int) {
|
||||
mappingsByIndex[index] = ReifiedTypeParameterMapping(name, null, newIndex)
|
||||
indexByParameterName[name] = index
|
||||
}
|
||||
|
||||
fun get(index: Int) = mappingsByIndex[index]
|
||||
fun get(name: String): ReifiedTypeParameterMapping? {
|
||||
return this[indexByParameterName[name] ?: return null]
|
||||
}
|
||||
}
|
||||
|
||||
public class ReifiedTypeParameterMapping(val name: String, val asmType: Type?, val newIndex: Int?)
|
||||
|
||||
private fun iconstInsn(n: Int): AbstractInsnNode {
|
||||
val node = MethodNode()
|
||||
InstructionAdapter(node).iconst(n)
|
||||
return node.instructions.getFirst()!!
|
||||
}
|
||||
Reference in New Issue
Block a user