Base support of StackValue.Property inlining

This commit is contained in:
Mikhael Bogdanov
2016-06-21 11:18:40 +03:00
parent d524a34fc7
commit 5a2e00d2ad
12 changed files with 244 additions and 46 deletions
@@ -2264,7 +2264,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
receiver = StackValue.receiverWithoutReceiverArgument(receiver); receiver = StackValue.receiverWithoutReceiverArgument(receiver);
} }
return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver); return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver, resolvedCall);
} }
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
@@ -2411,7 +2411,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Nullable ClassDescriptor superCallTarget, @Nullable ClassDescriptor superCallTarget,
@NotNull StackValue receiver @NotNull StackValue receiver
) { ) {
return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver); return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver, null);
} }
private CodegenContext getBackingFieldContext( private CodegenContext getBackingFieldContext(
@@ -2434,7 +2434,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
boolean syntheticBackingField, boolean syntheticBackingField,
@Nullable ClassDescriptor superCallTarget, @Nullable ClassDescriptor superCallTarget,
boolean skipAccessorsForPrivateFieldInOuterClass, boolean skipAccessorsForPrivateFieldInOuterClass,
StackValue receiver @NotNull StackValue receiver,
@Nullable ResolvedCall resolvedCall
) { ) {
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) { if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver); return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
@@ -2530,13 +2531,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return StackValue.property(propertyDescriptor, backingFieldOwner, return StackValue.property(propertyDescriptor, backingFieldOwner,
typeMapper.mapType( typeMapper.mapType(
isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver); isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall);
} }
@NotNull @NotNull
private StackValue.Property intermediateValueForSyntheticExtensionProperty( private StackValue.Property intermediateValueForSyntheticExtensionProperty(
@NotNull SyntheticJavaPropertyDescriptor propertyDescriptor, @NotNull SyntheticJavaPropertyDescriptor propertyDescriptor,
StackValue receiver @NotNull StackValue receiver
) { ) {
Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType()); Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType());
CallableMethod callableGetter = CallableMethod callableGetter =
@@ -2544,7 +2545,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
FunctionDescriptor setMethod = propertyDescriptor.getSetMethod(); FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
CallableMethod callableSetter = CallableMethod callableSetter =
setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null; setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver); return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this, null);
} }
@Override @Override
@@ -2831,8 +2832,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return getOrCreateCallGenerator(descriptor, function, null, true); return getOrCreateCallGenerator(descriptor, function, null, true);
} }
@NotNull
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) { CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
return getOrCreateCallGenerator(resolvedCall, resolvedCall.getResultingDescriptor());
}
@NotNull
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableDescriptor descriptor) {
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments(); Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
TypeParameterMappings mappings = new TypeParameterMappings(); TypeParameterMappings mappings = new TypeParameterMappings();
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) { for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
@@ -2858,8 +2863,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
); );
} }
} }
return getOrCreateCallGenerator( return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false);
resolvedCall.getResultingDescriptor(), resolvedCall.getCall().getCallElement(), mappings, false);
} }
@@ -391,7 +391,8 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
KtExpression initializer = property.getDelegateExpressionOrInitializer(); KtExpression initializer = property.getDelegateExpressionOrInitializer();
assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, false, null, true, StackValue.LOCAL_0); StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, false, null, true, StackValue.LOCAL_0,
null);
propValue.store(codegen.gen(initializer), codegen.v); propValue.store(codegen.gen(initializer), codegen.v);
} }
@@ -611,7 +612,8 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
syntheticBackingField || syntheticBackingField ||
original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY; original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY;
StackValue property = codegen.intermediateValueForProperty( StackValue property = codegen.intermediateValueForProperty(
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(), forceFieldForCompanionProperty, StackValue.none() original, forceField, syntheticBackingField, accessor.getSuperCallTarget(),
forceFieldForCompanionProperty, StackValue.none(), null
); );
InstructionAdapter iv = codegen.v; InstructionAdapter iv = codegen.v;
@@ -271,10 +271,11 @@ public abstract class StackValue {
@Nullable String fieldName, @Nullable String fieldName,
@Nullable CallableMethod getter, @Nullable CallableMethod getter,
@Nullable CallableMethod setter, @Nullable CallableMethod setter,
GenerationState state, @NotNull StackValue receiver,
@NotNull StackValue receiver @NotNull ExpressionCodegen codegen,
@Nullable ResolvedCall resolvedCall
) { ) {
return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, state, receiver); return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, receiver, codegen, resolvedCall);
} }
@NotNull @NotNull
@@ -1170,23 +1171,27 @@ public abstract class StackValue {
private final Type backingFieldOwner; private final Type backingFieldOwner;
private final PropertyDescriptor descriptor; private final PropertyDescriptor descriptor;
private final GenerationState state;
private final String fieldName; private final String fieldName;
@NotNull private final ExpressionCodegen codegen;
@Nullable private final ResolvedCall resolvedCall;
public Property( public Property(
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner, @NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
@Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField, @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
@Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state, @Nullable String fieldName, @NotNull Type type,
@NotNull StackValue receiver @NotNull StackValue receiver,
@NotNull ExpressionCodegen codegen,
@Nullable ResolvedCall resolvedCall
) { ) {
super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true); super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
this.backingFieldOwner = backingFieldOwner; this.backingFieldOwner = backingFieldOwner;
this.getter = getter; this.getter = getter;
this.setter = setter; this.setter = setter;
this.descriptor = descriptor; this.descriptor = descriptor;
this.state = state;
this.fieldName = fieldName; this.fieldName = fieldName;
this.codegen = codegen;
this.resolvedCall = resolvedCall;
} }
@Override @Override
@@ -1202,8 +1207,16 @@ public abstract class StackValue {
coerceTo(type, v); coerceTo(type, v);
} }
else { else {
getter.genInvokeInstruction(v); PropertyGetterDescriptor getter = descriptor.getGetter();
coerce(getter.getReturnType(), type, v); assert getter != null : "Getter descriptor should be not null for " + descriptor;
if (resolvedCall != null && getter.isInline()) {
CallGenerator callGenerator = codegen.getOrCreateCallGenerator(resolvedCall, getter);
callGenerator.putHiddenParams();
callGenerator.genCall(this.getter, resolvedCall, false, codegen);
} else {
this.getter.genInvokeInstruction(v);
}
coerce(this.getter.getReturnType(), type, v);
KotlinType returnType = descriptor.getReturnType(); KotlinType returnType = descriptor.getReturnType();
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) { if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
@@ -1245,6 +1258,23 @@ public abstract class StackValue {
v.mark(ok); v.mark(ok);
} }
@Override
public void store(@NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver) {
PropertySetterDescriptor setter = descriptor.getSetter();
if (resolvedCall != null && setter != null && setter.isInline()) {
assert this.setter != null : "Setter descriptor should be not null for " + descriptor;
CallGenerator callGenerator = codegen.getOrCreateCallGenerator(resolvedCall, setter);
if (!skipReceiver) {
putReceiver(v, false);
}
callGenerator.putHiddenParams();
callGenerator.putValueIfNeeded(rightSide.type, rightSide);
callGenerator.genCall(this.setter, resolvedCall, false, codegen);
} else {
super.store(rightSide, v, skipReceiver);
}
}
@Override @Override
public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) { public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
if (setter == null) { if (setter == null) {
@@ -115,7 +115,7 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
} }
public boolean isInlineMethodContext() { public boolean isInlineMethodContext() {
return InlineUtil.isInline(getContextDescriptor()); return InlineUtil.isInline(getFunctionDescriptor());
} }
@NotNull @NotNull
@@ -46,7 +46,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS; import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
import org.jetbrains.kotlin.types.expressions.LabelResolver; import org.jetbrains.kotlin.types.expressions.LabelResolver;
import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.Label;
@@ -211,8 +211,8 @@ public class InlineCodegen extends CallGenerator {
: jvmSignature.getAsmMethod(); : jvmSignature.getAsmMethod();
MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod); MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod);
final CallableMemberDescriptor directMember = JvmCodegenUtil.getDirectMember(functionDescriptor);
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor)) { if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(directMember instanceof DeserializedCallableMemberDescriptor)) {
return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod); return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod);
} }
@@ -220,7 +220,7 @@ public class InlineCodegen extends CallGenerator {
state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() { state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() {
@Override @Override
public SMAPAndMethodNode invoke() { public SMAPAndMethodNode invoke() {
SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(functionDescriptor, state, asmMethod); SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod);
if (result == null) { if (result == null) {
throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor); throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor);
} }
@@ -245,13 +245,13 @@ public class InlineCodegen extends CallGenerator {
@Nullable @Nullable
private static SMAPAndMethodNode doCreateMethodNodeFromCompiled( private static SMAPAndMethodNode doCreateMethodNodeFromCompiled(
@NotNull FunctionDescriptor functionDescriptor, @NotNull CallableMemberDescriptor callableDescriptor,
@NotNull final GenerationState state, @NotNull final GenerationState state,
@NotNull Method asmMethod @NotNull Method asmMethod
) { ) {
KotlinTypeMapper typeMapper = state.getTypeMapper(); KotlinTypeMapper typeMapper = state.getTypeMapper();
if (isBuiltInArrayIntrinsic(functionDescriptor)) { if (isBuiltInArrayIntrinsic(callableDescriptor)) {
ClassId classId = IntrinsicArrayConstructorsKt.getClassId(); ClassId classId = IntrinsicArrayConstructorsKt.getClassId();
byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0<byte[]>() { byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0<byte[]>() {
@Override @Override
@@ -263,10 +263,10 @@ public class InlineCodegen extends CallGenerator {
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state); return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state);
} }
assert functionDescriptor instanceof DeserializedSimpleFunctionDescriptor : "Not a deserialized function: " + functionDescriptor; assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor;
KotlinTypeMapper.ContainingClassesInfo containingClasses = KotlinTypeMapper.ContainingClassesInfo containingClasses =
typeMapper.getContainingClassesForDeserializedCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor); typeMapper.getContainingClassesForDeserializedCallable((DeserializedCallableMemberDescriptor) callableDescriptor);
final ClassId containerId = containingClasses.getImplClassId(); final ClassId containerId = containingClasses.getImplClassId();
@@ -292,7 +292,7 @@ public class InlineCodegen extends CallGenerator {
@NotNull @NotNull
private static SMAPAndMethodNode doCreateMethodNodeFromSource( private static SMAPAndMethodNode doCreateMethodNodeFromSource(
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor callableDescriptor,
@NotNull JvmMethodSignature jvmSignature, @NotNull JvmMethodSignature jvmSignature,
@NotNull ExpressionCodegen codegen, @NotNull ExpressionCodegen codegen,
@NotNull CodegenContext context, @NotNull CodegenContext context,
@@ -300,16 +300,16 @@ public class InlineCodegen extends CallGenerator {
@NotNull GenerationState state, @NotNull GenerationState state,
@NotNull Method asmMethod @NotNull Method asmMethod
) { ) {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor);
if (!(element instanceof KtNamedFunction)) { if (!(element instanceof KtNamedFunction || element instanceof KtPropertyAccessor)) {
throw new IllegalStateException("Couldn't find declaration for function " + functionDescriptor); throw new IllegalStateException("Couldn't find declaration for function " + callableDescriptor);
} }
KtNamedFunction inliningFunction = (KtNamedFunction) element; KtDeclarationWithBody inliningFunction = (KtDeclarationWithBody) element;
MethodNode node = new MethodNode( MethodNode node = new MethodNode(
InlineCodegenUtil.API, InlineCodegenUtil.API,
getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0), getMethodAsmFlags(callableDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0),
asmMethod.getName(), asmMethod.getName(),
asmMethod.getDescriptor(), asmMethod.getDescriptor(),
null, null null, null
@@ -319,23 +319,26 @@ public class InlineCodegen extends CallGenerator {
MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
CodegenContext parentContext = context.getParentContext(); CodegenContext parentContext = context.getParentContext();
assert parentContext != null : "Context has no parent: " + context; assert parentContext != null : "Context has no parent: " + context;
MethodContext methodContext = parentContext.intoFunction(functionDescriptor); MethodContext methodContext = parentContext.intoFunction(callableDescriptor);
SMAP smap; SMAP smap;
if (callDefault) { if (callDefault) {
Type implementationOwner = state.getTypeMapper().mapImplementationOwner(functionDescriptor); Type implementationOwner = state.getTypeMapper().mapImplementationOwner(callableDescriptor);
FakeMemberCodegen parentCodegen = new FakeMemberCodegen( FakeMemberCodegen parentCodegen = new FakeMemberCodegen(
codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(), codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(),
implementationOwner.getInternalName() implementationOwner.getInternalName()
); );
if (!(element instanceof KtNamedFunction)) {
throw new IllegalStateException("Propertiy accessors with default parameters not supported " + callableDescriptor);
}
FunctionCodegen.generateDefaultImplBody( FunctionCodegen.generateDefaultImplBody(
methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
inliningFunction, parentCodegen, asmMethod (KtNamedFunction) inliningFunction, parentCodegen, asmMethod
); );
smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
} }
else { else {
smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen); smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen);
} }
maxCalcAdapter.visitMaxs(-1, -1); maxCalcAdapter.visitMaxs(-1, -1);
maxCalcAdapter.visitEnd(); maxCalcAdapter.visitEnd();
@@ -343,11 +346,11 @@ public class InlineCodegen extends CallGenerator {
return new SMAPAndMethodNode(node, smap); return new SMAPAndMethodNode(node, smap);
} }
private static boolean isBuiltInArrayIntrinsic(@NotNull FunctionDescriptor functionDescriptor) { private static boolean isBuiltInArrayIntrinsic(@NotNull CallableMemberDescriptor callableDescriptor) {
if (functionDescriptor instanceof FictitiousArrayConstructor) return true; if (callableDescriptor instanceof FictitiousArrayConstructor) return true;
String name = functionDescriptor.getName().asString(); String name = callableDescriptor.getName().asString();
return (name.equals("arrayOf") || name.equals("emptyArray")) && return (name.equals("arrayOf") || name.equals("emptyArray")) &&
functionDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment; callableDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment;
} }
@NotNull @NotNull
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.jvm.BitEncoding import org.jetbrains.kotlin.serialization.jvm.BitEncoding
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmMethodSignature
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set<String> { fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set<String> {
@@ -31,12 +33,14 @@ fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set<String> {
return when (header.kind) { return when (header.kind) {
KotlinClassHeader.Kind.CLASS -> { KotlinClassHeader.Kind.CLASS -> {
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(BitEncoding.decodeBytes(annotationData), strings) val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(BitEncoding.decodeBytes(annotationData), strings)
inlineFunctionsJvmNames(classProto.functionList, nameResolver, classProto.typeTable) inlineFunctionsJvmNames(classProto.functionList, nameResolver, classProto.typeTable) +
inlineAccessorsJvmNames(classProto.propertyList, nameResolver)
} }
KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.FILE_FACADE,
KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(BitEncoding.decodeBytes(annotationData), strings) val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(BitEncoding.decodeBytes(annotationData), strings)
inlineFunctionsJvmNames(packageProto.functionList, nameResolver, packageProto.typeTable) inlineFunctionsJvmNames(packageProto.functionList, nameResolver, packageProto.typeTable) +
inlineAccessorsJvmNames(packageProto.propertyList, nameResolver)
} }
else -> emptySet() else -> emptySet()
} }
@@ -50,3 +54,27 @@ private fun inlineFunctionsJvmNames(functions: List<ProtoBuf.Function>, nameReso
} }
return jvmNames.toSet() return jvmNames.toSet()
} }
private fun inlineAccessorsJvmNames(properties: List<ProtoBuf.Property>, nameResolver: NameResolver): Set<String> {
val propertiesWithInlineAccessors = properties.filter { proto ->
proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags) ||
proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags)
}
val inlineAccessors = arrayListOf<JvmMethodSignature>()
propertiesWithInlineAccessors.forEach { proto ->
if (proto.hasExtension(JvmProtoBuf.propertySignature)) {
val signature = proto.getExtension(JvmProtoBuf.propertySignature)
if (proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags)) {
inlineAccessors.add(signature.getter)
}
if (proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags)) {
inlineAccessors.add(signature.setter)
}
}
}
return inlineAccessors.mapNotNull {
nameResolver.getString(it.name) + nameResolver.getString(it.desc)
}.toSet()
}
+25
View File
@@ -0,0 +1,25 @@
// FILE: 1.kt
package test
var value: Int = 0
inline var z: Int
get() = ++value
set(p: Int) { value = p }
// FILE: 2.kt
import test.*
fun box(): String {
val v = z
if (value != 1) return "fail 1: $value"
z = v + 2
if (value != 3) return "fail 2: $value"
var p = z
if (value != 4) return "fail 3: $value"
return "OK"
}
@@ -0,0 +1,25 @@
// FILE: 1.kt
package test
var value: Int = 0
inline var Int.z: Int
get() = this + ++value
set(p: Int) { value = p + this}
// FILE: 2.kt
import test.*
fun box(): String {
val v = 11.z
if (v != 12) return "fail 1: $v"
11.z = v + 2
if (value != 25) return "fail 2: $value"
var p = 11.z
if (p != 37) return "fail 3: $p"
return "OK"
}
@@ -0,0 +1,24 @@
package test
var value: Int = 0
inline var z: Int
get() = ++value
set(p: Int) { value = p }
fun box(): String {
val v = z
if (value != 1) return "fail 1: $value"
z = v + 2
if (value != 3) return "fail 2: $value"
var p = z
if (value != 4) return "fail 3: $value"
return "OK1"
}
// 0 SimpleKt.getZ
// 0 SimpleKt.setZ
@@ -1514,6 +1514,27 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/property")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Property extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/property"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simple.kt");
doTest(fileName);
}
@TestMetadata("simpleExtension.kt")
public void testSimpleExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simpleExtension.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified") @TestMetadata("compiler/testData/codegen/boxInline/reified")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1008,6 +1008,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/whenMappingOnCallSite.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/whenMappingOnCallSite.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/codegen/bytecodeText/inline/property")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Property extends AbstractBytecodeTextTest {
public void testAllFilesPresentInProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline/property"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/property/simple.kt");
doTest(fileName);
}
}
} }
@TestMetadata("compiler/testData/codegen/bytecodeText/interfaces") @TestMetadata("compiler/testData/codegen/bytecodeText/interfaces")
@@ -1514,6 +1514,27 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/property")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Property extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/property"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simple.kt");
doTest(fileName);
}
@TestMetadata("simpleExtension.kt")
public void testSimpleExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simpleExtension.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified") @TestMetadata("compiler/testData/codegen/boxInline/reified")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)