synthetic accessors for methods/properties are static methods in bytecode

This commit is contained in:
Alex Tkachman
2012-08-07 22:32:34 +03:00
parent 70c5a5ba9e
commit 8a29b8562d
9 changed files with 157 additions and 85 deletions
@@ -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.<AnnotationDescriptor>emptyList(),
Name.identifier(descriptor.getName() + "$b$" + index),
Kind.DECLARATION);
FunctionDescriptor fd = (SimpleFunctionDescriptor) descriptor;
initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null,
fd.getExpectedThisObject(),
Collections.<TypeParameterDescriptor>emptyList(),
fd.getValueParameters(),
fd.getReturnType(),
Modality.FINAL,
Visibilities.INTERNAL,
/*isInline = */ false);
}
}
@@ -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.<AnnotationDescriptor>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.<TypeParameterDescriptorImpl>emptyList(), pd.getExpectedThisObject(), receiverType);
initialize(new Getter(this), new Setter(this));
}
public static class Getter extends PropertyGetterDescriptor {
public Getter(AccessorForPropertyDescriptor property) {
super(property, Collections.<AnnotationDescriptor>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.<AnnotationDescriptor>emptyList(), Modality.FINAL, Visibilities.PUBLIC,
false,
false, Kind.DECLARATION);
}
}
}
@@ -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();
}
@@ -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<JetType,Integer> typeInfoConstants;
HashMap<Integer,JetType> reverseTypeInfoConstants;
int typeInfoConstantsCount;
HashMap<DeclarationDescriptor, DeclarationDescriptor> 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.<AnnotationDescriptor>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.<AnnotationDescriptor>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.<TypeParameterDescriptorImpl>emptyList(), pd.getExpectedThisObject(), receiverType);
PropertyGetterDescriptor pgd = new PropertyGetterDescriptor(
myAccessor, Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL,
Visibilities.PUBLIC,
false, false, CallableMemberDescriptor.Kind.DECLARATION);
pgd.initialize(myAccessor.getType());
PropertySetterDescriptor psd = new PropertySetterDescriptor(
myAccessor, Collections.<AnnotationDescriptor>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<? extends JetType> 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);
@@ -40,6 +40,9 @@ import java.util.List;
* @author Stepan Koltsov
*/
public class CodegenContexts {
private CodegenContexts() {
}
private static class FakeDescriptorForStaticContext implements DeclarationDescriptor {
@NotNull
@@ -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
@@ -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<ValueParameterDescriptor> 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);
@@ -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();
@@ -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() {