From 535cc3eed8765cd71aae54c9f386cc6dc002df0a Mon Sep 17 00:00:00 2001 From: Peter Rybin Date: Tue, 6 May 2014 03:01:43 +0400 Subject: [PATCH] Inline methods. --- .../codegen/ImplementationBodyCodegen.java | 461 +++++++++--------- 1 file changed, 220 insertions(+), 241 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 76461c67274..2f53a6ff13f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -625,7 +625,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new DataClassMethodGeneratorImpl(myClass, bindingContext).generate(); } - // A delegating class. Actual method implementations could easily move in. private class DataClassMethodGeneratorImpl extends DataClassMethodGenerator { DataClassMethodGeneratorImpl( JetClassOrObject klass, @@ -635,266 +634,246 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } @Override - public void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull ValueParameterDescriptor parameter) { - ImplementationBodyCodegen.this.generateComponentFunction(function, parameter); - } + public void generateEqualsMethod(@NotNull List properties) { + MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); + InstructionAdapter iv = new InstructionAdapter(mv); - @Override - public void generateCopyFunction(@NotNull FunctionDescriptor function, @NotNull List constructorParameters) { - ImplementationBodyCodegen.this.generateCopyFunction(function); - } + mv.visitCode(); + Label eq = new Label(); + Label ne = new Label(); - @Override - public void generateToStringMethod(@NotNull List properties) { - ImplementationBodyCodegen.this.generateDataClassToStringMethod(properties); + iv.load(0, OBJECT_TYPE); + iv.load(1, AsmTypeConstants.OBJECT_TYPE); + iv.ifacmpeq(eq); + + iv.load(1, AsmTypeConstants.OBJECT_TYPE); + iv.instanceOf(classAsmType); + iv.ifeq(ne); + + iv.load(1, AsmTypeConstants.OBJECT_TYPE); + iv.checkcast(classAsmType); + iv.store(2, AsmTypeConstants.OBJECT_TYPE); + + for (PropertyDescriptor propertyDescriptor : properties) { + Type asmType = typeMapper.mapType(propertyDescriptor); + + genPropertyOnStack(iv, propertyDescriptor, 0); + genPropertyOnStack(iv, propertyDescriptor, 2); + + if (asmType.getSort() == Type.ARRAY) { + Type elementType = correctElementType(asmType); + if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { + iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z"); + } + else { + iv.invokestatic("java/util/Arrays", "equals", "([" + elementType.getDescriptor() + "[" + elementType.getDescriptor() + ")Z"); + } + } + else { + StackValue value = genEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType); + value.put(Type.BOOLEAN_TYPE, iv); + } + + iv.ifeq(ne); + } + + iv.mark(eq); + iv.iconst(1); + iv.areturn(Type.INT_TYPE); + + iv.mark(ne); + iv.iconst(0); + iv.areturn(Type.INT_TYPE); + + FunctionCodegen.endVisit(mv, "equals", myClass); } @Override public void generateHashCodeMethod(@NotNull List properties) { - ImplementationBodyCodegen.this.generateDataClassHashCodeMethod(properties); + MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null); + InstructionAdapter iv = new InstructionAdapter(mv); + + mv.visitCode(); + boolean first = true; + for (PropertyDescriptor propertyDescriptor : properties) { + if (!first) { + iv.iconst(31); + iv.mul(Type.INT_TYPE); + } + + genPropertyOnStack(iv, propertyDescriptor, 0); + + Label ifNull = null; + Type asmType = typeMapper.mapType(propertyDescriptor); + if (!isPrimitive(asmType)) { + ifNull = new Label(); + iv.dup(); + iv.ifnull(ifNull); + } + + genHashCode(mv, iv, asmType); + + if (ifNull != null) { + Label end = new Label(); + iv.goTo(end); + iv.mark(ifNull); + iv.pop(); + iv.iconst(0); + iv.mark(end); + } + + if (first) { + first = false; + } + else { + iv.add(Type.INT_TYPE); + } + } + + mv.visitInsn(IRETURN); + + FunctionCodegen.endVisit(mv, "hashCode", myClass); } @Override - public void generateEqualsMethod(@NotNull List properties) { - ImplementationBodyCodegen.this.generateDataClassEqualsMethod(properties); - } - } + public void generateToStringMethod(@NotNull List properties) { + MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); + InstructionAdapter iv = new InstructionAdapter(mv); - private void generateDataClassEqualsMethod(@NotNull List properties) { - MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); - InstructionAdapter iv = new InstructionAdapter(mv); + mv.visitCode(); + genStringBuilderConstructor(iv); - mv.visitCode(); - Label eq = new Label(); - Label ne = new Label(); - - iv.load(0, OBJECT_TYPE); - iv.load(1, AsmTypeConstants.OBJECT_TYPE); - iv.ifacmpeq(eq); - - iv.load(1, AsmTypeConstants.OBJECT_TYPE); - iv.instanceOf(classAsmType); - iv.ifeq(ne); - - iv.load(1, AsmTypeConstants.OBJECT_TYPE); - iv.checkcast(classAsmType); - iv.store(2, AsmTypeConstants.OBJECT_TYPE); - - for (PropertyDescriptor propertyDescriptor : properties) { - Type asmType = typeMapper.mapType(propertyDescriptor); - - genPropertyOnStack(iv, propertyDescriptor, 0); - genPropertyOnStack(iv, propertyDescriptor, 2); - - if (asmType.getSort() == Type.ARRAY) { - Type elementType = correctElementType(asmType); - if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { - iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z"); + boolean first = true; + for (PropertyDescriptor propertyDescriptor : properties) { + if (first) { + iv.aconst(descriptor.getName() + "(" + propertyDescriptor.getName().asString()+"="); + first = false; } else { - iv.invokestatic("java/util/Arrays", "equals", "([" + elementType.getDescriptor() + "[" + elementType.getDescriptor() + ")Z"); + iv.aconst(", " + propertyDescriptor.getName().asString()+"="); } - } - else { - StackValue value = genEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType); - value.put(Type.BOOLEAN_TYPE, iv); - } + genInvokeAppendMethod(iv, JAVA_STRING_TYPE); - iv.ifeq(ne); - } + Type type = genPropertyOnStack(iv, propertyDescriptor, 0); - iv.mark(eq); - iv.iconst(1); - iv.areturn(Type.INT_TYPE); - - iv.mark(ne); - iv.iconst(0); - iv.areturn(Type.INT_TYPE); - - FunctionCodegen.endVisit(mv, "equals", myClass); - } - - private void generateDataClassHashCodeMethod(@NotNull List properties) { - MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null); - InstructionAdapter iv = new InstructionAdapter(mv); - - mv.visitCode(); - boolean first = true; - for (PropertyDescriptor propertyDescriptor : properties) { - if (!first) { - iv.iconst(31); - iv.mul(Type.INT_TYPE); - } - - genPropertyOnStack(iv, propertyDescriptor, 0); - - Label ifNull = null; - Type asmType = typeMapper.mapType(propertyDescriptor); - if (!isPrimitive(asmType)) { - ifNull = new Label(); - iv.dup(); - iv.ifnull(ifNull); - } - - genHashCode(mv, iv, asmType); - - if (ifNull != null) { - Label end = new Label(); - iv.goTo(end); - iv.mark(ifNull); - iv.pop(); - iv.iconst(0); - iv.mark(end); - } - - if (first) { - first = false; - } - else { - iv.add(Type.INT_TYPE); - } - } - - mv.visitInsn(IRETURN); - - FunctionCodegen.endVisit(mv, "hashCode", myClass); - } - - private void generateDataClassToStringMethod(@NotNull List properties) { - MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); - InstructionAdapter iv = new InstructionAdapter(mv); - - mv.visitCode(); - genStringBuilderConstructor(iv); - - boolean first = true; - for (PropertyDescriptor propertyDescriptor : properties) { - if (first) { - iv.aconst(descriptor.getName() + "(" + propertyDescriptor.getName().asString()+"="); - first = false; - } - else { - iv.aconst(", " + propertyDescriptor.getName().asString()+"="); - } - genInvokeAppendMethod(iv, JAVA_STRING_TYPE); - - Type type = genPropertyOnStack(iv, propertyDescriptor, 0); - - if (type.getSort() == Type.ARRAY) { - Type elementType = correctElementType(type); - if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { - iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;"); - type = JAVA_STRING_TYPE; - } - else { - if (elementType.getSort() != Type.CHAR) { - iv.invokestatic("java/util/Arrays", "toString", "(" + type.getDescriptor() + ")Ljava/lang/String;"); + if (type.getSort() == Type.ARRAY) { + Type elementType = correctElementType(type); + if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { + iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;"); type = JAVA_STRING_TYPE; } - } - } - genInvokeAppendMethod(iv, type); - } - - iv.aconst(")"); - genInvokeAppendMethod(iv, JAVA_STRING_TYPE); - - iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); - iv.areturn(JAVA_STRING_TYPE); - - FunctionCodegen.endVisit(mv, "toString", myClass); - } - - private Type genPropertyOnStack(InstructionAdapter iv, PropertyDescriptor propertyDescriptor, int index) { - iv.load(index, classAsmType); - //noinspection ConstantConditions - Method method = typeMapper.mapSignature(propertyDescriptor.getGetter()).getAsmMethod(); - - iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor()); - return method.getReturnType(); - } - - private void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull final ValueParameterDescriptor parameter) { - functionCodegen.generateMethod(myClass, typeMapper.mapSignature(function), function, new FunctionGenerationStrategy() { - @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context, - @Nullable MemberCodegen parentCodegen - ) { - Type componentType = signature.getReturnType(); - InstructionAdapter iv = new InstructionAdapter(mv); - if (!componentType.equals(Type.VOID_TYPE)) { - iv.load(0, classAsmType); - String desc = "()" + componentType.getDescriptor(); - iv.invokevirtual(classAsmType.getInternalName(), PropertyCodegen.getterName(parameter.getName()), desc); - } - iv.areturn(componentType); - } - }); - } - - private void generateCopyFunction(@NotNull final FunctionDescriptor function) { - JvmMethodSignature methodSignature = typeMapper.mapSignature(function); - - final Type thisDescriptorType = typeMapper.mapType(descriptor); - - functionCodegen.generateMethod(myClass, methodSignature, function, new FunctionGenerationStrategy() { - @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context, - @Nullable MemberCodegen parentCodegen - ) { - InstructionAdapter iv = new InstructionAdapter(mv); - - iv.anew(thisDescriptorType); - iv.dup(); - - ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(descriptor); - assert function.getValueParameters().size() == constructor.getValueParameters().size() : - "Number of parameters of copy function and constructor are different. " + - "Copy: " + function.getValueParameters().size() + ", " + - "constructor: " + constructor.getValueParameters().size(); - - MutableClosure closure = ImplementationBodyCodegen.this.context.closure; - if (closure != null && closure.getCaptureThis() != null) { - Type type = typeMapper.mapType(enclosingClassDescriptor(bindingContext, descriptor)); - iv.load(0, classAsmType); - iv.getfield(classAsmType.getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor()); - } - - int parameterIndex = 1; // localVariable 0 = this - for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) { - Type type = typeMapper.mapType(parameterDescriptor.getType()); - iv.load(parameterIndex, type); - parameterIndex += type.getSize(); - } - - String constructorJvmDescriptor = typeMapper.mapToCallableMethod(constructor).getAsmMethod().getDescriptor(); - iv.invokespecial(thisDescriptorType.getInternalName(), "", constructorJvmDescriptor); - - iv.areturn(thisDescriptorType); - } - }); - - functionCodegen.generateDefaultIfNeeded( - context.intoFunction(function), methodSignature, function, OwnerKind.IMPLEMENTATION, - new DefaultParameterValueLoader() { - @Override - public void putValueOnStack(ValueParameterDescriptor valueParameter, ExpressionCodegen codegen) { - assert KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration()) - : "Function container should be annotated with [data]: " + function; - PropertyDescriptor property = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter); - assert property != null : "Copy function doesn't correspond to any property: " + function; - codegen.v.load(0, thisDescriptorType); - Type propertyType = typeMapper.mapType(property); - codegen.intermediateValueForProperty(property, false, null).put(propertyType, codegen.v); + else { + if (elementType.getSort() != Type.CHAR) { + iv.invokestatic("java/util/Arrays", "toString", "(" + type.getDescriptor() + ")Ljava/lang/String;"); + type = JAVA_STRING_TYPE; + } } } - ); + genInvokeAppendMethod(iv, type); + } + + iv.aconst(")"); + genInvokeAppendMethod(iv, JAVA_STRING_TYPE); + + iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); + iv.areturn(JAVA_STRING_TYPE); + + FunctionCodegen.endVisit(mv, "toString", myClass); + } + + private Type genPropertyOnStack(InstructionAdapter iv, PropertyDescriptor propertyDescriptor, int index) { + iv.load(index, classAsmType); + //noinspection ConstantConditions + Method method = typeMapper.mapSignature(propertyDescriptor.getGetter()).getAsmMethod(); + + iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor()); + return method.getReturnType(); + } + + @Override + public void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull final ValueParameterDescriptor parameter) { + functionCodegen.generateMethod(myClass, typeMapper.mapSignature(function), function, new FunctionGenerationStrategy() { + @Override + public void generateBody( + @NotNull MethodVisitor mv, + @NotNull JvmMethodSignature signature, + @NotNull MethodContext context1, + @Nullable MemberCodegen parentCodegen + ) { + Type componentType = signature.getReturnType(); + InstructionAdapter iv = new InstructionAdapter(mv); + if (!componentType.equals(Type.VOID_TYPE)) { + iv.load(0, classAsmType); + String desc = "()" + componentType.getDescriptor(); + iv.invokevirtual(classAsmType.getInternalName(), PropertyCodegen.getterName(parameter.getName()), desc); + } + iv.areturn(componentType); + } + }); + } + + @Override + public void generateCopyFunction(@NotNull final FunctionDescriptor function, @NotNull List constructorParameters) { + JvmMethodSignature methodSignature = typeMapper.mapSignature(function); + + final Type thisDescriptorType = typeMapper.mapType(descriptor); + + functionCodegen.generateMethod(myClass, methodSignature, function, new FunctionGenerationStrategy() { + @Override + public void generateBody( + @NotNull MethodVisitor mv, + @NotNull JvmMethodSignature signature, + @NotNull MethodContext context1, + @Nullable MemberCodegen parentCodegen + ) { + InstructionAdapter iv = new InstructionAdapter(mv); + + iv.anew(thisDescriptorType); + iv.dup(); + + ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(descriptor); + assert function.getValueParameters().size() == constructor.getValueParameters().size() : + "Number of parameters of copy function and constructor are different. " + + "Copy: " + function.getValueParameters().size() + ", " + + "constructor: " + constructor.getValueParameters().size(); + + MutableClosure closure = ImplementationBodyCodegen.this.context.closure; + if (closure != null && closure.getCaptureThis() != null) { + Type type = typeMapper.mapType(enclosingClassDescriptor(bindingContext, descriptor)); + iv.load(0, classAsmType); + iv.getfield(classAsmType.getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor()); + } + + int parameterIndex = 1; // localVariable 0 = this + for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) { + Type type = typeMapper.mapType(parameterDescriptor.getType()); + iv.load(parameterIndex, type); + parameterIndex += type.getSize(); + } + + String constructorJvmDescriptor = typeMapper.mapToCallableMethod(constructor).getAsmMethod().getDescriptor(); + iv.invokespecial(thisDescriptorType.getInternalName(), "", constructorJvmDescriptor); + + iv.areturn(thisDescriptorType); + } + }); + + functionCodegen.generateDefaultIfNeeded( + context.intoFunction(function), methodSignature, function, OwnerKind.IMPLEMENTATION, + new DefaultParameterValueLoader() { + @Override + public void putValueOnStack(ValueParameterDescriptor valueParameter, ExpressionCodegen codegen) { + assert KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration()) + : "Function container should be annotated with [data]: " + function; + PropertyDescriptor property = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter); + assert property != null : "Copy function doesn't correspond to any property: " + function; + codegen.v.load(0, thisDescriptorType); + Type propertyType = typeMapper.mapType(property); + codegen.intermediateValueForProperty(property, false, null).put(propertyType, codegen.v); + } + } + ); + } } private void generateEnumMethodsAndConstInitializers() {