diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt new file mode 100644 index 00000000000..1f0842a0bf2 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2015 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.kotlin.codegen + +import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.state.JetTypeMapper +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.psi.JetClass +import org.jetbrains.kotlin.psi.JetClassOrObject +import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +public class DefaultParameterValueSubstitutor(val state: GenerationState) { + fun generateDefaultConstructorIfNeeded(method: CallableMethod, + constructorDescriptor: ConstructorDescriptor, + classBuilder: ClassBuilder, + classOrObject: JetClassOrObject) { + if (!isEmptyConstructorNeeded(constructorDescriptor, classOrObject)) { + return + } + + val flags = AsmUtil.getVisibilityAccessFlag(constructorDescriptor) + val mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "", "()V", null, + FunctionCodegen.getThrownExceptions(constructorDescriptor, state.getTypeMapper())) + + if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return + + val v = InstructionAdapter(mv) + mv.visitCode() + + val methodOwner = method.getOwner() + v.load(0, methodOwner) // Load this on stack + + var mask = 0 + val masks = arrayListOf() + for (parameterDescriptor in constructorDescriptor.getValueParameters()) { + val paramType = state.getTypeMapper().mapType(parameterDescriptor.getType()) + AsmUtil.pushDefaultValueOnStack(paramType, v) + val i = parameterDescriptor.getIndex() + if (i != 0 && i % Integer.SIZE == 0) { + masks.add(mask) + mask = 0 + } + mask = mask or (1 shl (i % Integer.SIZE)) + } + masks.add(mask) + for (m in masks) { + v.iconst(m) + } + + // constructors with default arguments has last synthetic argument of specific type + v.aconst(null) + + val desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false) + v.invokespecial(methodOwner.getInternalName(), "", desc, false) + v.areturn(Type.VOID_TYPE) + FunctionCodegen.endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject) + } + + private fun isEmptyConstructorNeeded(constructorDescriptor: ConstructorDescriptor, classOrObject: JetClassOrObject): Boolean { + val classDescriptor = constructorDescriptor.getContainingDeclaration() + + if (classOrObject.isLocal()) return false + + if (CodegenBinding.canHaveOuter(state.getBindingContext(), classDescriptor)) return false + + if (Visibilities.isPrivate(classDescriptor.getVisibility()) || Visibilities.isPrivate(constructorDescriptor.getVisibility())) + return false + + if (constructorDescriptor.getValueParameters().isEmpty()) return false + if (classOrObject is JetClass && hasSecondaryConstructorsWithNoParameters(classOrObject)) return false + + return constructorDescriptor.getValueParameters().all { it.declaresDefaultValue() } + } + + private fun hasSecondaryConstructorsWithNoParameters(klass: JetClass) = + klass.getSecondaryConstructors().any { it.getValueParameters().isEmpty() } + +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index a4ae796a485..d82f0c8d50f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.bridges.Bridge; import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.context.MethodContext; import org.jetbrains.kotlin.codegen.context.PackageContext; @@ -39,10 +38,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage; import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.psi.JetClass; -import org.jetbrains.kotlin.psi.JetClassOrObject; import org.jetbrains.kotlin.psi.JetNamedFunction; -import org.jetbrains.kotlin.psi.JetSecondaryConstructor; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; @@ -68,7 +64,10 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*; @@ -548,54 +547,6 @@ public class FunctionCodegen { return ArrayUtil.toStringArray(strings); } - static void generateConstructorWithoutParametersIfNeeded( - @NotNull GenerationState state, - @NotNull CallableMethod method, - @NotNull ConstructorDescriptor constructorDescriptor, - @NotNull ClassBuilder classBuilder, - @NotNull JetClassOrObject classOrObject - ) { - if (!isEmptyConstructorNeeded(state.getBindingContext(), constructorDescriptor, classOrObject)) { - return; - } - int flags = getVisibilityAccessFlag(constructorDescriptor); - MethodVisitor mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "", "()V", null, - getThrownExceptions(constructorDescriptor, state.getTypeMapper())); - - if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return; - - InstructionAdapter v = new InstructionAdapter(mv); - mv.visitCode(); - - Type methodOwner = method.getOwner(); - v.load(0, methodOwner); // Load this on stack - - int mask = 0; - List masks = new ArrayList(1); - for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { - Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType()); - pushDefaultValueOnStack(paramType, v); - int i = parameterDescriptor.getIndex(); - if (i != 0 && i % Integer.SIZE == 0) { - masks.add(mask); - mask = 0; - } - mask |= (1 << (i % Integer.SIZE)); - } - masks.add(mask); - for (int m : masks) { - v.iconst(m); - } - - // constructors with default arguments has last synthetic argument of specific type - v.aconst(null); - - String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false); - v.invokespecial(methodOwner.getInternalName(), "", desc, false); - v.areturn(Type.VOID_TYPE); - endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject); - } - void generateDefaultIfNeeded( @NotNull MethodContext owner, @NotNull FunctionDescriptor functionDescriptor, @@ -775,38 +726,6 @@ public class FunctionCodegen { return needed; } - private static boolean isEmptyConstructorNeeded( - @NotNull BindingContext context, - @NotNull ConstructorDescriptor constructorDescriptor, - @NotNull JetClassOrObject classOrObject - ) { - ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration(); - - if (classOrObject.isLocal()) return false; - - if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false; - - if (Visibilities.isPrivate(classDescriptor.getVisibility()) || - Visibilities.isPrivate(constructorDescriptor.getVisibility())) return false; - - if (constructorDescriptor.getValueParameters().isEmpty()) return false; - if (classOrObject instanceof JetClass && hasSecondaryConstructorsWithNoParameters((JetClass) classOrObject)) return false; - - for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { - if (!parameterDescriptor.declaresDefaultValue()) { - return false; - } - } - return true; - } - - private static boolean hasSecondaryConstructorsWithNoParameters(@NotNull JetClass klass) { - for (JetSecondaryConstructor constructor : klass.getSecondaryConstructors()) { - if (constructor.getValueParameters().isEmpty()) return true; - } - return false; - } - private void generateBridge( @Nullable PsiElement origin, @NotNull FunctionDescriptor descriptor, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index ce1ae36c3ed..1b4cee481c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1077,7 +1077,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { DefaultParameterValueLoader.DEFAULT, null); CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor); - FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v, myClass); + new DefaultParameterValueSubstitutor(state).generateDefaultConstructorIfNeeded(callableMethod, constructorDescriptor, v, myClass); if (isCompanionObject(descriptor)) { context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);