extract code for generating parameterless constructor into a separate class and rewrite it in Kotlin
This commit is contained in:
@@ -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, "<init>", "()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<Int>()
|
||||||
|
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(), "<init>", 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() }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
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.CodegenContext;
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||||
import org.jetbrains.kotlin.codegen.context.PackageContext;
|
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.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
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.JetNamedFunction;
|
||||||
import org.jetbrains.kotlin.psi.JetSecondaryConstructor;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
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.PrintWriter;
|
||||||
import java.io.StringWriter;
|
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.AsmUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
||||||
@@ -548,54 +547,6 @@ public class FunctionCodegen {
|
|||||||
return ArrayUtil.toStringArray(strings);
|
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, "<init>", "()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<Integer> masks = new ArrayList<Integer>(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(), "<init>", desc, false);
|
|
||||||
v.areturn(Type.VOID_TYPE);
|
|
||||||
endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
void generateDefaultIfNeeded(
|
void generateDefaultIfNeeded(
|
||||||
@NotNull MethodContext owner,
|
@NotNull MethodContext owner,
|
||||||
@NotNull FunctionDescriptor functionDescriptor,
|
@NotNull FunctionDescriptor functionDescriptor,
|
||||||
@@ -775,38 +726,6 @@ public class FunctionCodegen {
|
|||||||
return needed;
|
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(
|
private void generateBridge(
|
||||||
@Nullable PsiElement origin,
|
@Nullable PsiElement origin,
|
||||||
@NotNull FunctionDescriptor descriptor,
|
@NotNull FunctionDescriptor descriptor,
|
||||||
|
|||||||
@@ -1077,7 +1077,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
DefaultParameterValueLoader.DEFAULT, null);
|
DefaultParameterValueLoader.DEFAULT, null);
|
||||||
|
|
||||||
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor);
|
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||||
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v, myClass);
|
new DefaultParameterValueSubstitutor(state).generateDefaultConstructorIfNeeded(callableMethod, constructorDescriptor, v, myClass);
|
||||||
|
|
||||||
if (isCompanionObject(descriptor)) {
|
if (isCompanionObject(descriptor)) {
|
||||||
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);
|
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);
|
||||||
|
|||||||
Reference in New Issue
Block a user