Supported reification for anonymous objects and lambdas

This commit is contained in:
Denis Zharkov
2014-10-13 19:01:41 +04:00
committed by Andrey Breslav
parent a689f6d243
commit 21699e1753
20 changed files with 476 additions and 82 deletions
@@ -17,16 +17,18 @@
package org.jetbrains.jet.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConstructorInvocation {
public class AnonymousObjectGeneration {
private final String ownerInternalName;
private final String desc;
private final String constructorDesc;
private final Map<Integer, LambdaInfo> lambdasToInline;
@@ -41,19 +43,39 @@ public class ConstructorInvocation {
private Map<String, LambdaInfo> capturedLambdasToInline;
private final boolean capturedOuterRegenerated;
private final boolean needReification;
private final boolean alreadyRegenerated;
private final boolean isStaticOrigin;
ConstructorInvocation(
AnonymousObjectGeneration(
@NotNull String ownerInternalName,
@NotNull String desc,
@NotNull Map<Integer, LambdaInfo> lambdasToInline,
boolean needReification,
boolean isSameModule,
boolean capturedOuterRegenerated
@NotNull Map<Integer, LambdaInfo> lambdasToInline,
boolean capturedOuterRegenerated,
boolean alreadyRegenerated,
@Nullable String constructorDesc,
boolean isStaticOrigin
) {
this.ownerInternalName = ownerInternalName;
this.desc = desc;
this.constructorDesc = constructorDesc;
this.lambdasToInline = lambdasToInline;
this.isSameModule = isSameModule;
this.capturedOuterRegenerated = capturedOuterRegenerated;
this.needReification = needReification;
this.alreadyRegenerated = alreadyRegenerated;
this.isStaticOrigin = isStaticOrigin;
}
public AnonymousObjectGeneration(
@NotNull String ownerInternalName, boolean isSameModule, boolean needReification,
boolean alreadyRegenerated,
boolean isStaticOrigin
) {
this(
ownerInternalName, isSameModule, needReification,
new HashMap<Integer, LambdaInfo>(), false, alreadyRegenerated, null, isStaticOrigin
);
}
public String getOwnerInternalName() {
@@ -61,7 +83,9 @@ public class ConstructorInvocation {
}
public boolean shouldRegenerate() {
return !lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated;
return !alreadyRegenerated && (
!lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated || needReification
);
}
public Map<Integer, LambdaInfo> getLambdasToInline() {
@@ -100,7 +124,12 @@ public class ConstructorInvocation {
this.capturedLambdasToInline = capturedLambdasToInline;
}
public String getDesc() {
return desc;
@Nullable
public String getConstructorDesc() {
return constructorDesc;
}
public boolean isStaticOrigin() {
return isStaticOrigin;
}
}
@@ -79,10 +79,21 @@ public class AnonymousObjectTransformer {
}
@NotNull
public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) {
public InlineResult doTransform(@NotNull final AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) {
ClassBuilder classBuilder = createClassBuilder();
final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();
final InlineResult result = InlineResult.create();
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
@Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
if (signature != null) {
ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature);
signature = signatureResult.getNewSignature();
result.markAsNeededFurtherReificationIf(signatureResult.getNeedFurtherReification());
}
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public void visitOuterClass(@NotNull String owner, String name, String desc) {
@@ -131,46 +142,47 @@ public class AnonymousObjectTransformer {
ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
List<CapturedParamInfo> additionalFakeParams =
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation);
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen);
InlineResult result = InlineResult.create();
for (MethodNode next : methodsToTransform) {
MethodVisitor visitor = newMethod(classBuilder, next);
InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, allCapturedParamBuilder);
InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, visitor, next, allCapturedParamBuilder);
result.addAllClassesToRemove(funResult);
result.markAsNeededFurtherReificationIf(funResult.needFurtherReification());
}
InlineResult constructorResult =
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper, additionalFakeParams);
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams);
result.addAllClassesToRemove(constructorResult);
classBuilder.done();
invocation.setNewLambdaType(newLambdaType);
anonymousObjectGen.setNewLambdaType(newLambdaType);
return result;
}
@NotNull
private InlineResult inlineMethod(
@NotNull ConstructorInvocation invocation,
@NotNull AnonymousObjectGeneration anonymousObjectGen,
@NotNull FieldRemapper parentRemapper,
@NotNull MethodVisitor resultVisitor,
@NotNull MethodNode sourceNode,
@NotNull ParametersBuilder capturedBuilder
) {
boolean neededFurtherReification = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions);
Parameters parameters = getMethodParametersWithCaptured(capturedBuilder, sourceNode);
RegeneratedLambdaFieldRemapper remapper =
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
parameters, invocation.getCapturedLambdasToInline(),
parameters, anonymousObjectGen.getCapturedLambdasToInline(),
parentRemapper);
MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for " + invocation.getOwnerInternalName());
remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName());
InlineResult result = inliner.doInline(resultVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE);
result.markAsNeededFurtherReificationIf(neededFurtherReification);
resultVisitor.visitMaxs(-1, -1);
resultVisitor.visitEnd();
return result;
@@ -180,7 +192,7 @@ public class AnonymousObjectTransformer {
@NotNull ClassBuilder classBuilder,
@NotNull ParametersBuilder allCapturedBuilder,
@NotNull ParametersBuilder constructorInlineBuilder,
@NotNull ConstructorInvocation invocation,
@NotNull AnonymousObjectGeneration anonymousObjectGen,
@NotNull FieldRemapper parentRemapper,
@NotNull List<CapturedParamInfo> constructorAdditionalFakeParams
) {
@@ -251,11 +263,11 @@ public class AnonymousObjectTransformer {
RegeneratedLambdaFieldRemapper remapper =
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
constructorParameters, invocation.getCapturedLambdasToInline(),
constructorParameters, anonymousObjectGen.getCapturedLambdasToInline(),
parentRemapper);
MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for constructor of " + invocation.getOwnerInternalName());
remapper, isSameModule, "Transformer for constructor of " + anonymousObjectGen.getOwnerInternalName());
InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false,
LabelOwner.NOT_APPLICABLE);
constructorVisitor.visitMaxs(-1, -1);
@@ -263,7 +275,7 @@ public class AnonymousObjectTransformer {
AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder);
//TODO for inline method make public class
invocation.setNewConstructorDescriptor(constructorDescriptor);
anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor);
return result;
}
@@ -302,19 +314,19 @@ public class AnonymousObjectTransformer {
@NotNull MethodNode constructor,
@NotNull ParametersBuilder capturedParamBuilder,
@NotNull ParametersBuilder constructorParamBuilder,
@NotNull final ConstructorInvocation invocation
@NotNull final AnonymousObjectGeneration anonymousObjectGen
) {
CapturedParamOwner owner = new CapturedParamOwner() {
@Override
public Type getType() {
return Type.getObjectType(invocation.getOwnerInternalName());
return Type.getObjectType(anonymousObjectGen.getOwnerInternalName());
}
};
List<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>();
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
Map<Integer, LambdaInfo> indexToLambda = anonymousObjectGen.getLambdasToInline();
Set<Integer> capturedParams = new HashSet<Integer>();
//load captured parameters and patch instruction list (NB: there is also could be object fields)
@@ -355,7 +367,14 @@ public class AnonymousObjectTransformer {
}
constructorParamBuilder.addThis(oldObjectType, false);
Type [] types = Type.getArgumentTypes(invocation.getDesc());
String constructorDesc = anonymousObjectGen.getConstructorDesc();
if (constructorDesc == null) {
// in case of anonymous object with empty closure
constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE);
}
Type [] types = Type.getArgumentTypes(constructorDesc);
for (Type type : types) {
LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null);
@@ -389,8 +408,8 @@ public class AnonymousObjectTransformer {
invocation.setAllRecapturedParameters(allRecapturedParameters);
invocation.setCapturedLambdasToInline(capturedLambdasToInline);
anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters);
anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline);
return constructorAdditionalFakeParams;
}
@@ -222,7 +222,7 @@ public class InlineCodegen implements CallGenerator {
.subGenerator(functionDescriptor.getName().asString()),
codegen.getContext(),
callElement,
codegen.getParentCodegen().getClassName());
codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText()); //with captured
@@ -232,6 +232,10 @@ public class InlineCodegenUtil {
return "<init>".equals(methodName) && isAnonymousClass(internalName);
}
public static boolean isAnonymousSingletonLoad(@NotNull String internalName, @NotNull String fieldName) {
return JvmAbi.INSTANCE_FIELD.equals(fieldName) && isAnonymousClass(internalName);
}
public static boolean isAnonymousClass(String internalName) {
String shortName = getLastNamePart(internalName);
int index = shortName.lastIndexOf("$");
@@ -24,6 +24,7 @@ import java.util.Set;
public class InlineResult {
private final Set<String> classesToRemove = new HashSet<String>();
private boolean needFurtherReification = false;
private InlineResult() {
@@ -48,4 +49,12 @@ public class InlineResult {
public Set<String> getClassesToRemove() {
return classesToRemove;
}
public boolean needFurtherReification() {
return needFurtherReification;
}
public void markAsNeededFurtherReificationIf(boolean condtition) {
this.needFurtherReification |= condtition;
}
}
@@ -37,6 +37,8 @@ public class InliningContext {
public final Map<String, String> typeMapping;
public final ReifiedTypeInliner reifedTypeInliner;
public final boolean isInliningLambda;
public final boolean classRegeneration;
@@ -47,6 +49,7 @@ public class InliningContext {
@NotNull GenerationState state,
@NotNull NameGenerator nameGenerator,
@NotNull Map<String, String> typeMapping,
@NotNull ReifiedTypeInliner reifedTypeInliner,
boolean isInliningLambda,
boolean classRegeneration
) {
@@ -55,6 +58,7 @@ public class InliningContext {
this.state = state;
this.nameGenerator = nameGenerator;
this.typeMapping = typeMapping;
this.reifedTypeInliner = reifedTypeInliner;
this.isInliningLambda = isInliningLambda;
this.classRegeneration = classRegeneration;
}
@@ -75,11 +79,12 @@ public class InliningContext {
public InliningContext subInlineWithClassRegeneration(@NotNull NameGenerator generator,
@NotNull Map<String, String> additionalTypeMappings,
@NotNull ConstructorInvocation constructorInvocation) {
@NotNull AnonymousObjectGeneration anonymousObjectGeneration
) {
Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
newTypeMappings.putAll(additionalTypeMappings);
return new RegenetedClassContext(this, expressionMap, state, generator,
newTypeMappings, isInliningLambda, constructorInvocation);
newTypeMappings, reifedTypeInliner, isInliningLambda, anonymousObjectGeneration);
}
@@ -96,7 +101,7 @@ public class InliningContext {
Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
newTypeMappings.putAll(additionalTypeMappings);
return new InliningContext(this, expressionMap, state, generator,
newTypeMappings, isInliningLambda, isRegeneration);
newTypeMappings, reifedTypeInliner, isInliningLambda, isRegeneration);
}
public boolean isRoot() {
@@ -29,10 +29,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
import org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter;
@@ -62,7 +59,7 @@ public class MethodInliner {
private final List<InvokeCall> invokeCalls = new ArrayList<InvokeCall>();
//keeps order
private final List<ConstructorInvocation> constructorInvocations = new ArrayList<ConstructorInvocation>();
private final List<AnonymousObjectGeneration> anonymousObjectGenerations = new ArrayList<AnonymousObjectGeneration>();
//current state
private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
@@ -140,44 +137,55 @@ public class MethodInliner {
final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
final Iterator<ConstructorInvocation> iterator = constructorInvocations.iterator();
final Iterator<AnonymousObjectGeneration> iterator = anonymousObjectGenerations.iterator();
RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode,
new TypeRemapper(currentTypeMapping));
InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.totalSize()) {
private ConstructorInvocation invocation;
private AnonymousObjectGeneration anonymousObjectGen;
private void handleAnonymousObjectGeneration() {
anonymousObjectGen = iterator.next();
if (anonymousObjectGen.shouldRegenerate()) {
//TODO: need poping of type but what to do with local funs???
Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName());
currentTypeMapping.put(anonymousObjectGen.getOwnerInternalName(), newLambdaType.getInternalName());
AnonymousObjectTransformer transformer =
new AnonymousObjectTransformer(anonymousObjectGen.getOwnerInternalName(),
inliningContext
.subInlineWithClassRegeneration(
inliningContext.nameGenerator,
currentTypeMapping,
anonymousObjectGen),
isSameModule, newLambdaType
);
InlineResult transformResult = transformer.doTransform(anonymousObjectGen, nodeRemapper);
result.addAllClassesToRemove(transformResult);
if (inliningContext.isInliningLambda && !anonymousObjectGen.isStaticOrigin()) {
// this class is transformed and original not used so we should remove original one after inlining
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
// because it can be local function from outer scope
result.addClassToRemove(anonymousObjectGen.getOwnerInternalName());
}
if (transformResult.needFurtherReification()) {
ReifiedTypeInliner.putNeedClassReificationMarker(mv);
result.markAsNeededFurtherReificationIf(true);
}
}
}
@Override
public void anew(@NotNull Type type) {
if (isAnonymousConstructorCall(type.getInternalName(), "<init>")) {
invocation = iterator.next();
if (invocation.shouldRegenerate()) {
//TODO: need poping of type but what to do with local funs???
Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName());
currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName());
AnonymousObjectTransformer transformer =
new AnonymousObjectTransformer(invocation.getOwnerInternalName(),
inliningContext
.subInlineWithClassRegeneration(
inliningContext.nameGenerator,
currentTypeMapping,
invocation),
isSameModule, newLambdaType
);
InlineResult transformResult = transformer.doTransform(invocation, nodeRemapper);
result.addAllClassesToRemove(transformResult);
if (inliningContext.isInliningLambda) {
//this class is transformed and original not used so we should remove original one after inlining
result.addClassToRemove(invocation.getOwnerInternalName());
}
}
handleAnonymousObjectGeneration();
}
//in case of regenerated invocation type would be remapped to new one via remappingMethodAdapter
//in case of regenerated anonymousObjectGen type would be remapped to new one via remappingMethodAdapter
super.anew(type);
}
@@ -222,24 +230,35 @@ public class MethodInliner {
addInlineMarker(this, false);
}
else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
if (invocation.shouldRegenerate()) {
assert anonymousObjectGen != null : "<init> call not corresponds to new call" + owner + " " + name;
if (anonymousObjectGen.shouldRegenerate()) {
//put additional captured parameters on stack
for (CapturedParamDesc capturedParamDesc : invocation.getAllRecapturedParameters()) {
for (CapturedParamDesc capturedParamDesc : anonymousObjectGen.getAllRecapturedParameters()) {
visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(),
"$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor());
}
super.visitMethodInsn(opcode, invocation.getNewLambdaType().getInternalName(), name, invocation.getNewConstructorDescriptor(), itf);
invocation = null;
super.visitMethodInsn(opcode, anonymousObjectGen.getNewLambdaType().getInternalName(), name, anonymousObjectGen.getNewConstructorDescriptor(), itf);
anonymousObjectGen = null;
} else {
super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
}
}
else if (ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) {
// we will put it if needed in anew processing
}
else {
super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
}
}
@Override
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
if (opcode == Opcodes.GETSTATIC && isAnonymousSingletonLoad(owner, name)) {
handleAnonymousObjectGeneration();
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitMaxs(int stack, int locals) {
lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
@@ -358,11 +377,17 @@ public class MethodInliner {
AbstractInsnNode cur = node.instructions.getFirst();
int index = 0;
boolean awaitClassReification = false;
Set<LabelNode> possibleDeadLabels = new HashSet<LabelNode>();
while (cur != null) {
Frame<SourceValue> frame = sources[index];
if (frame != null) {
if (cur.getType() == AbstractInsnNode.METHOD_INSN) {
if (ReifiedTypeInliner.isNeedClassReificationMarker(cur)) {
awaitClassReification = true;
}
else if (cur.getType() == AbstractInsnNode.METHOD_INSN) {
MethodInsnNode methodInsnNode = (MethodInsnNode) cur;
String owner = methodInsnNode.owner;
String desc = methodInsnNode.desc;
@@ -403,11 +428,27 @@ public class MethodInliner {
}
}
constructorInvocations.add(new ConstructorInvocation(owner, desc, lambdaMapping, isSameModule, inliningContext.classRegeneration));
anonymousObjectGenerations.add(
buildConstructorInvocation(
owner, desc, lambdaMapping, awaitClassReification
)
);
awaitClassReification = false;
}
}
else if (cur.getOpcode() == Opcodes.GETSTATIC) {
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
String owner = fieldInsnNode.owner;
if (isAnonymousSingletonLoad(owner, fieldInsnNode.name)) {
anonymousObjectGenerations.add(
new AnonymousObjectGeneration(
owner, isSameModule, awaitClassReification, isAlreadyRegenerated(owner), true
)
);
awaitClassReification = false;
}
}
}
AbstractInsnNode prevNode = cur;
cur = cur.getNext();
index++;
@@ -446,6 +487,26 @@ public class MethodInliner {
return start == end;
}
@NotNull
private AnonymousObjectGeneration buildConstructorInvocation(
@NotNull String owner,
@NotNull String desc,
@NotNull Map<Integer, LambdaInfo> lambdaMapping,
boolean needReification
) {
return new AnonymousObjectGeneration(
owner, needReification, isSameModule, lambdaMapping,
inliningContext.classRegeneration,
isAlreadyRegenerated(owner),
desc,
false
);
}
private boolean isAlreadyRegenerated(@NotNull String owner) {
return inliningContext.typeMapping.containsKey(owner);
}
public LambdaInfo getLambdaIfExists(AbstractInsnNode insnNode) {
if (insnNode.getOpcode() == Opcodes.ALOAD) {
int varIndex = ((VarInsnNode) insnNode).var;
@@ -25,7 +25,7 @@ import java.util.Map;
public class RegenetedClassContext extends InliningContext {
@NotNull
private final ConstructorInvocation constructorInvocation;
private final AnonymousObjectGeneration anonymousObjectGeneration;
protected RegenetedClassContext(
@Nullable InliningContext parent,
@@ -33,15 +33,16 @@ public class RegenetedClassContext extends InliningContext {
@NotNull GenerationState state,
@NotNull NameGenerator nameGenerator,
@NotNull Map<String, String> typeMapping,
@NotNull ReifiedTypeInliner reifiedTypeInliner,
boolean isInliningLambda,
@NotNull ConstructorInvocation constructorInvocation
@NotNull AnonymousObjectGeneration anonymousObjectGeneration
) {
super(parent, map, state, nameGenerator, typeMapping, isInliningLambda, true);
this.constructorInvocation = constructorInvocation;
super(parent, map, state, nameGenerator, typeMapping, reifiedTypeInliner, isInliningLambda, true);
this.anonymousObjectGeneration = anonymousObjectGeneration;
}
@Override
public String getClassNameToInline() {
return constructorInvocation.getOwnerInternalName();
return anonymousObjectGeneration.getOwnerInternalName();
}
}
@@ -38,9 +38,10 @@ public class RootInliningContext extends InliningContext {
@NotNull NameGenerator nameGenerator,
@NotNull CodegenContext startContext,
@NotNull JetElement callElement,
@NotNull String classNameToInline
@NotNull String classNameToInline,
@NotNull ReifiedTypeInliner inliner
) {
super(null, map, state, nameGenerator, Collections.<String, String>emptyMap(), false, false);
super(null, map, state, nameGenerator, Collections.<String, String>emptyMap(), inliner, false, false);
this.callElement = callElement;
this.startContext = startContext;
this.classNameToInline = classNameToInline;
@@ -0,0 +1,14 @@
import kotlin.test.assertEquals
inline fun foo(x: String, block: (String) -> String) = block(x)
fun box(): String {
val res = foo("abc") {
fun bar(y: String) = y + "cde"
bar(it)
}
assertEquals("abccde", res)
return "OK"
}
@@ -0,0 +1,14 @@
import kotlin.test.assertEquals
inline fun foo(x: String, block: (String) -> String) = block(x)
fun box(): String {
val res = foo("abc") {
fun bar(y: String) = y + "cde"
foo(it) { bar(it) }
}
assertEquals("abccde", res)
return "OK"
}
@@ -0,0 +1,15 @@
import kotlin.test.assertEquals
inline fun foo(x: String, block: (String) -> String) = block(x)
fun noInlineFoo(x: String, block: (String) -> String) = block(x)
fun box(): String {
val res = foo("abc") {
fun bar(y: String) = y + "cde"
noInlineFoo(it) { bar(it) }
}
assertEquals("abccde", res)
return "OK"
}
@@ -0,0 +1,13 @@
import kotlin.test.assertEquals
inline fun foo(x: String, block: (String) -> String) = block(x)
fun box(): String {
fun bar(y: String) = y + "cde"
val res = foo("abc") { bar(it) }
assertEquals("abccde", res)
return "OK"
}
@@ -0,0 +1,19 @@
import kotlin.test.assertEquals
abstract class A {
abstract fun f(): String
}
inline fun<reified T> foo(): A {
return object : A() {
override fun f(): String {
return javaClass<T>().getName()
}
}
}
fun box(): String {
val y = foo<String>();
assertEquals("java.lang.String", y.f())
return "OK"
}
@@ -0,0 +1,20 @@
import kotlin.test.assertEquals
abstract class A<R> {
abstract fun f(): String
}
inline fun<reified T> foo(): A<T> {
return object : A<T>() {
override fun f(): String {
return "OK"
}
}
}
fun box(): String {
val y = foo<String>();
assertEquals("OK", y.f())
assertEquals("A<java.lang.String>", y.javaClass.getGenericSuperclass()?.toString())
return "OK"
}
@@ -0,0 +1,27 @@
import kotlin.test.assertEquals
abstract class A<R> {
abstract fun f(): String
override fun toString() = f()
}
abstract class G {
abstract fun bar(): Any
}
inline fun<reified T> foo(): G {
return object : G() {
override fun bar(): Any {
return object : A<T>() {
override fun f(): String = "OK"
}
}
}
}
fun box(): String {
val y = foo<String>().bar();
assertEquals("OK", y.toString())
assertEquals("A<java.lang.String>", y.javaClass.getGenericSuperclass()?.toString())
return "OK"
}
@@ -0,0 +1,17 @@
import kotlin.test.assertEquals
fun foo(block: () -> String) = block()
inline fun<reified T> bar1(x: T): String = foo() {
javaClass<T>().getName()
}
inline fun<reified T> bar2(x: T, y: String): String = foo() {
javaClass<T>().getName() + "#" + y
}
fun box(): String {
assertEquals("java.lang.Integer", bar1(1))
assertEquals("java.lang.String#OK", bar2("abc", "OK"))
return "OK"
}
@@ -0,0 +1,35 @@
import kotlin.test.assertEquals
abstract class A<R> {
abstract fun f(): String
override fun toString() = f()
}
abstract class G {
abstract fun bar(): Any
}
inline fun<reified T> baz(): G {
return object : G() {
override fun bar(): Any {
return object : A<T>() {
override fun f(): String = "OK"
}
}
}
}
inline fun<T1, T2, T3, T4, T5, T6, reified R1, reified R2> foo(): Pair<G, G> {
return Pair(baz<R1>(), baz<R2>())
}
fun box(): String {
val res = foo<Int, Int, Int, Int, Int, Int, Int, String>();
val x1 = res.first.bar()
val x2 = res.second.bar()
assertEquals("OK", x1.toString())
assertEquals("OK", x2.toString())
assertEquals("A<java.lang.Integer>", x1.javaClass.getGenericSuperclass()?.toString())
assertEquals("A<java.lang.String>", x2.javaClass.getGenericSuperclass()?.toString())
return "OK"
}
@@ -0,0 +1,22 @@
import kotlin.test.assertEquals
fun foo(block: () -> String) = block()
inline fun<reified T> bar1(): String = foo() {
javaClass<T>().getName()
}
inline fun<reified T> bar2(y: String): String = foo() {
javaClass<T>().getName() + "#" + y
}
inline fun<T1, T2, reified R1, reified R2> bar3(y: String) =
Pair(bar1<R1>(), bar2<R2>(y))
fun box(): String {
val x = bar3<Any, Double, Int, String>("OK")
assertEquals("java.lang.Integer", x.first)
assertEquals("java.lang.String#OK", x.second)
return "OK"
}
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/boxWithStdlib")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Enum.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.NonLocalReturns.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformTypes.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Reified.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class})
@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Enum.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.LocalFunInLambda.class, BlackBoxWithStdlibCodegenTestGenerated.NonLocalReturns.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformTypes.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Reified.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class})
@RunWith(JUnit3RunnerWithInners.class)
public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInBoxWithStdlib() throws Exception {
@@ -1452,6 +1452,39 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class LocalFunInLambda extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInLocalFunInLambda() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/localFunInLambda"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("definedWithinLambda.kt")
public void testDefinedWithinLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("definedWithinLambdaInnerUsage1.kt")
public void testDefinedWithinLambdaInnerUsage1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("definedWithinLambdaInnerUsage2.kt")
public void testDefinedWithinLambdaInnerUsage2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/nonLocalReturns")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2420,6 +2453,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reified"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("anonymousObject.kt")
public void testAnonymousObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("anonymousObjectReifiedSupertype.kt")
public void testAnonymousObjectReifiedSupertype() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("checkcast.kt")
public void testCheckcast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/checkcast.kt");
@@ -2438,6 +2483,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("innerAnonymousObject.kt")
public void testInnerAnonymousObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("instanceof.kt")
public void testInstanceof() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/instanceof.kt");
@@ -2456,12 +2507,30 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("nonInlineableLambdaInReifiedFunction.kt")
public void testNonInlineableLambdaInReifiedFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("recursiveInnerAnonymousObject.kt")
public void testRecursiveInnerAnonymousObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("recursiveNewArray.kt")
public void testRecursiveNewArray() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveNewArray.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("recursiveNonInlineableLambda.kt")
public void testRecursiveNonInlineableLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("safecast.kt")
public void testSafecast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/safecast.kt");