From 8a29b8562dbb787d2a4dbaed28b32ed7eaef4b46 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 7 Aug 2012 22:32:34 +0300 Subject: [PATCH] synthetic accessors for methods/properties are static methods in bytecode --- .../AccessorForFunctionDescriptor.java | 45 ++++++++++++ .../AccessorForPropertyDescriptor.java | 56 +++++++++++++++ .../jetbrains/jet/codegen/CallableMethod.java | 7 +- .../jetbrains/jet/codegen/CodegenContext.java | 68 +------------------ .../jet/codegen/CodegenContexts.java | 3 + .../codegen/ImplementationBodyCodegen.java | 14 ++-- .../jetbrains/jet/codegen/JetTypeMapper.java | 39 +++++++++-- .../jetbrains/jet/codegen/StubCodegen.java | 3 + .../jet/codegen/CodegenTestCase.java | 7 +- 9 files changed, 157 insertions(+), 85 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/AccessorForFunctionDescriptor.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForFunctionDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForFunctionDescriptor.java new file mode 100644 index 00000000000..87735e64197 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForFunctionDescriptor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2012 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.jet.codegen; + +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.Collections; + +/** + * @author alex.tkachman +*/ +public class AccessorForFunctionDescriptor extends SimpleFunctionDescriptorImpl { + public AccessorForFunctionDescriptor(DeclarationDescriptor descriptor, DeclarationDescriptor containingDeclaration, int index) { + super(containingDeclaration, Collections.emptyList(), + Name.identifier(descriptor.getName() + "$b$" + index), + Kind.DECLARATION); + + FunctionDescriptor fd = (SimpleFunctionDescriptor) descriptor; + + initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null, + fd.getExpectedThisObject(), + Collections.emptyList(), + fd.getValueParameters(), + fd.getReturnType(), + Modality.FINAL, + Visibilities.INTERNAL, + /*isInline = */ false); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java new file mode 100644 index 00000000000..fad288fc832 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2012 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.jet.codegen; + +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collections; + +/** + * @author alex.tkachman +*/ +public class AccessorForPropertyDescriptor extends PropertyDescriptor { + public AccessorForPropertyDescriptor(PropertyDescriptor pd, DeclarationDescriptor containingDeclaration, int index) { + super(containingDeclaration, Collections.emptyList(), Modality.FINAL, Visibilities.PUBLIC, + pd.isVar(), pd.isObjectDeclaration(), Name.identifier(pd.getName() + "$b$" + index), + Kind.DECLARATION); + + JetType receiverType = pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null; + setType(pd.getType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); + initialize(new Getter(this), new Setter(this)); + } + + public static class Getter extends PropertyGetterDescriptor { + public Getter(AccessorForPropertyDescriptor property) { + super(property, Collections.emptyList(), Modality.FINAL, Visibilities.PUBLIC, + false, + false, Kind.DECLARATION); + initialize(property.getType()); + } + } + + public static class Setter extends PropertySetterDescriptor { + public Setter(AccessorForPropertyDescriptor property) { + super(property, Collections.emptyList(), Modality.FINAL, Visibilities.PUBLIC, + false, + false, Kind.DECLARATION); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index f49e5489faa..4137ddfd573 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -67,7 +67,7 @@ public class CallableMethod implements Callable { return owner; } - @NotNull + @Nullable public JvmClassName getDefaultImplParam() { return defaultImplParam; } @@ -96,6 +96,7 @@ public class CallableMethod implements Callable { v.visitMethodInsn(getInvokeOpcode(), owner.getInternalName(), getSignature().getAsmMethod().getName(), getSignature().getAsmMethod().getDescriptor()); } + @Nullable public Type getGenerateCalleeType() { return generateCalleeType; } @@ -122,10 +123,6 @@ public class CallableMethod implements Callable { return thisClass != null && generateCalleeType == null; } - public boolean isNeedsReceiver() { - return receiverParameterType != null; - } - public Type getReturnType() { return signature.getAsmMethod().getReturnType(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index 4f76c0d8c39..382fa0221fe 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -20,9 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; @@ -43,9 +41,6 @@ public abstract class CodegenContext { private final CodegenContext parentContext; public final ObjectOrClosureCodegen closure; - HashMap typeInfoConstants; - HashMap reverseTypeInfoConstants; - int typeInfoConstantsCount; HashMap accessors; protected StackValue outerExpression; @@ -183,50 +178,10 @@ public abstract class CodegenContext { if (accessor != null) { return accessor; } if (descriptor instanceof SimpleFunctionDescriptor) { - SimpleFunctionDescriptorImpl myAccessor = new SimpleFunctionDescriptorImpl(contextDescriptor, - Collections.emptyList(), - Name.identifier(descriptor.getName() + "$b$" + getHierarchyCount() + "$" + accessors.size()), - CallableMemberDescriptor.Kind.DECLARATION); - FunctionDescriptor fd = (SimpleFunctionDescriptor) descriptor; - myAccessor.initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null, - fd.getExpectedThisObject(), - fd.getTypeParameters(), - fd.getValueParameters(), - fd.getReturnType(), - Modality.FINAL, - Visibilities.PUBLIC, - /*isInline = */ false); - accessor = myAccessor; + accessor = new AccessorForFunctionDescriptor(descriptor, contextDescriptor, accessors.size()); } else if (descriptor instanceof PropertyDescriptor) { - PropertyDescriptor pd = (PropertyDescriptor) descriptor; - PropertyDescriptor myAccessor = new PropertyDescriptor(contextDescriptor, - Collections.emptyList(), - Modality.FINAL, - Visibilities.PUBLIC, - pd.isVar(), - pd.isObjectDeclaration(), - Name.identifier(pd.getName() + "$b$" + getHierarchyCount() + "$" + accessors.size()), - CallableMemberDescriptor.Kind.DECLARATION - ); - JetType receiverType = pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null; - myAccessor.setType(pd.getType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); - - PropertyGetterDescriptor pgd = new PropertyGetterDescriptor( - myAccessor, Collections.emptyList(), - Modality.FINAL, - Visibilities.PUBLIC, - false, false, CallableMemberDescriptor.Kind.DECLARATION); - pgd.initialize(myAccessor.getType()); - - PropertySetterDescriptor psd = new PropertySetterDescriptor( - myAccessor, Collections.emptyList(), - Modality.FINAL, - Visibilities.PUBLIC, - false, false, CallableMemberDescriptor.Kind.DECLARATION); - - myAccessor.initialize(pgd, psd); - accessor = myAccessor; + accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor,accessors.size()); } else { throw new UnsupportedOperationException(); @@ -235,25 +190,6 @@ public abstract class CodegenContext { return accessor; } - private int getHierarchyCount() { - ClassDescriptor descriptor = getThisDescriptor(); - int c = 0; - while(descriptor != null) { - Collection supertypes = descriptor.getDefaultType().getConstructor().getSupertypes(); - if (supertypes.isEmpty()) { - break; - } - c++; - for (JetType supertype : supertypes) { - descriptor = (ClassDescriptor) supertype.getConstructor().getDeclarationDescriptor(); - if (descriptor.getKind() == ClassKind.CLASS) { - break; - } - } - } - return c; - } - public StackValue getReceiverExpression(JetTypeMapper typeMapper) { assert getReceiverDescriptor() != null; Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java index bcb43beb1c9..03aa14cadc5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java @@ -40,6 +40,9 @@ import java.util.List; * @author Stepan Koltsov */ public class CodegenContexts { + private CodegenContexts() { + } + private static class FakeDescriptorForStaticContext implements DeclarationDescriptor { @NotNull diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index e259def68f1..6ec6e1f811a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -312,7 +312,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method originalMethod = typeMapper.mapSignature(original.getName(), original).getAsmMethod(); Type[] argTypes = method.getArgumentTypes(); - MethodVisitor mv = v.newMethod(null, ACC_BRIDGE | ACC_FINAL, bridge.getName().getName(), method.getDescriptor(), null, null); + String owner = typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION).getInternalName(); + MethodVisitor mv = v.newMethod(null, ACC_BRIDGE | ACC_SYNTHETIC | ACC_STATIC, bridge.getName().getName(), + method.getDescriptor(), null, null); if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { StubCodegen.generateStubCode(mv); } @@ -322,13 +324,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { InstructionAdapter iv = new InstructionAdapter(mv); iv.load(0, JetTypeMapper.TYPE_OBJECT); - for (int i = 0, reg = 1; i < argTypes.length; i++) { + for (int i = 1, reg = 1; i < argTypes.length; i++) { Type argType = argTypes[i]; iv.load(reg, argType); //noinspection AssignmentToForLoopParameter reg += argType.getSize(); } - iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION).getInternalName(), originalMethod.getName(), originalMethod.getDescriptor()); + iv.invokespecial(owner, originalMethod.getName(), originalMethod.getDescriptor()); iv.areturn(method.getReturnType()); FunctionCodegen.endVisit(iv, "accessor", null); @@ -342,7 +344,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method method = typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod(); JvmPropertyAccessorSignature originalSignature = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION); Method originalMethod = originalSignature.getJvmMethodSignature().getAsmMethod(); - MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_BRIDGE | ACC_FINAL, method.getName(), method.getDescriptor(), null, null); + MethodVisitor mv = v.newMethod(null, ACC_BRIDGE | ACC_STATIC, method.getName(), method.getDescriptor(), null, null); PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature.getPropertyTypeKotlinSignature(), originalSignature.getJvmMethodSignature().getKotlinTypeParameter(), original, ((PropertyDescriptor) entry.getValue()).getGetter().getVisibility()); @@ -370,7 +372,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod(); JvmPropertyAccessorSignature originalSignature2 = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION); Method originalMethod = originalSignature2.getJvmMethodSignature().getAsmMethod(); - MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_BRIDGE | ACC_FINAL, method.getName(), method.getDescriptor(), null, null); + MethodVisitor mv = v.newMethod(null, ACC_STATIC | ACC_BRIDGE | ACC_FINAL, method.getName(), method.getDescriptor(), null, null); PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature2.getPropertyTypeKotlinSignature(), originalSignature2.getJvmMethodSignature().getKotlinTypeParameter(), original, ((PropertyDescriptor) entry.getValue()).getSetter().getVisibility()); @@ -384,7 +386,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(0, JetTypeMapper.TYPE_OBJECT); Type[] argTypes = method.getArgumentTypes(); - for (int i = 0, reg = 1; i < argTypes.length; i++) { + for (int i = 1, reg = 1; i < argTypes.length; i++) { Type argType = argTypes[i]; iv.load(reg, argType); //noinspection AssignmentToForLoopParameter diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 11e8445e0e9..957c3bcbd6d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -38,7 +38,6 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.lang.types.lang.JetStandardLibraryNames; import org.jetbrains.jet.lang.types.lang.PrimitiveType; import org.jetbrains.jet.lang.types.ref.ClassName; @@ -611,6 +610,8 @@ public class JetTypeMapper { boolean originalIsInterface = CodegenUtil.isInterface(declarationOwner); boolean currentIsInterface = CodegenUtil.isInterface(currentOwner); + boolean isAccessor = isAccessor(functionDescriptor); + ClassDescriptor receiver; if (currentIsInterface && !originalIsInterface) { receiver = declarationOwner; @@ -630,7 +631,7 @@ public class JetTypeMapper { invokeOpcode = isInterface ? (superCall ? Opcodes.INVOKESTATIC : Opcodes.INVOKEINTERFACE) - : (superCall ? Opcodes.INVOKESPECIAL : Opcodes.INVOKEVIRTUAL); + : (isAccessor ? Opcodes.INVOKESTATIC : (superCall ? Opcodes.INVOKESPECIAL : Opcodes.INVOKEVIRTUAL)); if (isInterface && superCall) { descriptor = mapSignature(functionDescriptor, false, OwnerKind.TRAIT_IMPL); owner = JvmClassName.byInternalName(owner.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX); @@ -653,7 +654,11 @@ public class JetTypeMapper { owner, ownerForDefaultImpl, ownerForDefaultParam, descriptor, invokeOpcode, thisClass, receiverParameterType, null); } - + + private static boolean isAccessor(FunctionDescriptor functionDescriptor) { + return functionDescriptor instanceof AccessorForFunctionDescriptor || functionDescriptor instanceof AccessorForPropertyDescriptor.Getter || functionDescriptor instanceof AccessorForPropertyDescriptor.Setter; + } + @NotNull private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) { //if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { @@ -682,6 +687,12 @@ public class JetTypeMapper { signatureVisitor.writeParametersStart(); + if(isAccessor(f)) { + signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS); + mapType(((ClassifierDescriptor)f.getContainingDeclaration()).getDefaultType(), signatureVisitor, MapTypeMode.VALUE); + signatureVisitor.writeParameterTypeEnd(); + } + if (kind == OwnerKind.TRAIT_IMPL) { ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration); @@ -784,7 +795,13 @@ public class JetTypeMapper { writeFormalTypeParameters(f.getTypeParameters(), signatureWriter); signatureWriter.writeParametersStart(); - + + if(isAccessor(f)) { + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS); + mapType(((ClassifierDescriptor)f.getContainingDeclaration()).getDefaultType(), signatureWriter, MapTypeMode.VALUE); + signatureWriter.writeParameterTypeEnd(); + } + final List parameters = f.getValueParameters(); if (receiver.exists()) { signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); @@ -826,6 +843,13 @@ public class JetTypeMapper { mapType(containingDeclaration.getDefaultType(), signatureWriter, MapTypeMode.IMPL); signatureWriter.writeParameterTypeEnd(); } + else { + if(descriptor instanceof AccessorForPropertyDescriptor) { + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS); + mapType(((ClassifierDescriptor)descriptor.getContainingDeclaration()).getDefaultType(), signatureWriter, MapTypeMode.VALUE); + signatureWriter.writeParameterTypeEnd(); + } + } if (descriptor.getReceiverParameter().exists()) { signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); @@ -866,6 +890,13 @@ public class JetTypeMapper { mapType(containingDeclaration.getDefaultType(), signatureWriter, MapTypeMode.VALUE); signatureWriter.writeParameterTypeEnd(); } + else { + if(descriptor instanceof AccessorForPropertyDescriptor) { + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS); + mapType(((ClassifierDescriptor)descriptor.getContainingDeclaration()).getDefaultType(), signatureWriter, MapTypeMode.VALUE); + signatureWriter.writeParameterTypeEnd(); + } + } if (descriptor.getReceiverParameter().exists()) { signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StubCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/StubCodegen.java index 734786acf63..1b6fd156bb2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StubCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StubCodegen.java @@ -24,6 +24,9 @@ import org.jetbrains.asm4.commons.InstructionAdapter; * @author Stepan Koltsov */ public class StubCodegen { + private StubCodegen() { + } + public static void generateStubThrow(MethodVisitor mv) { new InstructionAdapter(mv).anew(Type.getObjectType("java/lang/RuntimeException")); new InstructionAdapter(mv).dup(); diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index c88277058d1..321ce3a8eea 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -274,10 +274,9 @@ public abstract class CodegenTestCase extends UsefulTestCase { BuiltinsScopeExtensionMode.ALL); analyzeExhaust.throwIfError(); AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext()); - GenerationState state = new GenerationState(myEnvironment.getProject(), classBuilderFactory, analyzeExhaust, myFiles.getPsiFiles()); - state.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); - alreadyGenerated = state; - return state; + alreadyGenerated = new GenerationState(myEnvironment.getProject(), classBuilderFactory, analyzeExhaust, myFiles.getPsiFiles()); + alreadyGenerated.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); + return alreadyGenerated; } protected Class generateNamespaceClass() {