001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.codegen; 018 019 import com.intellij.openapi.util.Pair; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.asm4.Type; 023 import org.jetbrains.asm4.commons.Method; 024 import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf; 025 import org.jetbrains.jet.descriptors.serialization.NameTable; 026 import org.jetbrains.jet.descriptors.serialization.ProtoBuf; 027 import org.jetbrains.jet.descriptors.serialization.SerializerExtension; 028 import org.jetbrains.jet.lang.descriptors.*; 029 import org.jetbrains.jet.lang.resolve.name.FqName; 030 import org.jetbrains.jet.lang.resolve.name.Name; 031 032 import java.util.Arrays; 033 034 import static org.jetbrains.jet.codegen.JvmSerializationBindings.*; 035 036 public class JavaSerializerExtension extends SerializerExtension { 037 private final JvmSerializationBindings bindings; 038 039 public JavaSerializerExtension(@NotNull JvmSerializationBindings bindings) { 040 this.bindings = bindings; 041 } 042 043 @Override 044 public void serializeCallable( 045 @NotNull CallableMemberDescriptor callable, 046 @NotNull ProtoBuf.Callable.Builder proto, 047 @NotNull NameTable nameTable 048 ) { 049 saveSignature(callable, proto, nameTable); 050 saveImplClassName(callable, proto, nameTable); 051 } 052 053 @Override 054 public void serializeValueParameter( 055 @NotNull ValueParameterDescriptor descriptor, 056 @NotNull ProtoBuf.Callable.ValueParameter.Builder proto, 057 @NotNull NameTable nameTable 058 ) { 059 Integer index = bindings.get(INDEX_FOR_VALUE_PARAMETER, descriptor); 060 if (index != null) { 061 proto.setExtension(JavaProtoBuf.index, index); 062 } 063 } 064 065 private void saveSignature( 066 @NotNull CallableMemberDescriptor callable, 067 @NotNull ProtoBuf.Callable.Builder proto, 068 @NotNull NameTable nameTable 069 ) { 070 if (callable instanceof FunctionDescriptor) { 071 Method method = bindings.get(METHOD_FOR_FUNCTION, (FunctionDescriptor) callable); 072 if (method != null) { 073 proto.setExtension(JavaProtoBuf.methodSignature, new SignatureSerializer(nameTable).methodSignature(method)); 074 } 075 } 076 else if (callable instanceof PropertyDescriptor) { 077 PropertyDescriptor property = (PropertyDescriptor) callable; 078 079 PropertyGetterDescriptor getter = property.getGetter(); 080 PropertySetterDescriptor setter = property.getSetter(); 081 Method getterMethod = getter == null ? null : bindings.get(METHOD_FOR_FUNCTION, getter); 082 Method setterMethod = setter == null ? null : bindings.get(METHOD_FOR_FUNCTION, setter); 083 084 Pair<Type, String> field = bindings.get(FIELD_FOR_PROPERTY, property); 085 Type fieldType; 086 String fieldName; 087 boolean isStaticInOuter; 088 Method syntheticMethod; 089 if (field != null) { 090 fieldType = field.first; 091 fieldName = field.second; 092 isStaticInOuter = bindings.get(STATIC_FIELD_IN_OUTER_CLASS, property); 093 syntheticMethod = null; 094 } 095 else { 096 fieldType = null; 097 fieldName = null; 098 isStaticInOuter = false; 099 syntheticMethod = bindings.get(SYNTHETIC_METHOD_FOR_PROPERTY, property); 100 } 101 102 JavaProtoBuf.JavaPropertySignature signature = new SignatureSerializer(nameTable) 103 .propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getterMethod, setterMethod); 104 proto.setExtension(JavaProtoBuf.propertySignature, signature); 105 } 106 } 107 108 private void saveImplClassName( 109 @NotNull CallableMemberDescriptor callable, 110 @NotNull ProtoBuf.Callable.Builder proto, 111 @NotNull NameTable nameTable 112 ) { 113 String name = bindings.get(IMPL_CLASS_NAME_FOR_CALLABLE, callable); 114 if (name != null) { 115 proto.setExtension(JavaProtoBuf.implClassName, nameTable.getSimpleNameIndex(Name.identifier(name))); 116 } 117 } 118 119 private static class SignatureSerializer { 120 private final NameTable nameTable; 121 122 public SignatureSerializer(@NotNull NameTable nameTable) { 123 this.nameTable = nameTable; 124 } 125 126 @NotNull 127 public JavaProtoBuf.JavaMethodSignature methodSignature(@NotNull Method method) { 128 JavaProtoBuf.JavaMethodSignature.Builder signature = JavaProtoBuf.JavaMethodSignature.newBuilder(); 129 130 signature.setName(nameTable.getSimpleNameIndex(Name.guess(method.getName()))); 131 132 signature.setReturnType(type(method.getReturnType())); 133 134 for (Type type : method.getArgumentTypes()) { 135 signature.addParameterType(type(type)); 136 } 137 138 return signature.build(); 139 } 140 141 @NotNull 142 public JavaProtoBuf.JavaPropertySignature propertySignature( 143 @Nullable Type fieldType, 144 @Nullable String fieldName, 145 boolean isStaticInOuter, 146 @Nullable Method syntheticMethod, 147 @Nullable Method getter, 148 @Nullable Method setter 149 ) { 150 JavaProtoBuf.JavaPropertySignature.Builder signature = JavaProtoBuf.JavaPropertySignature.newBuilder(); 151 152 if (fieldType != null) { 153 assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldType; 154 signature.setField(fieldSignature(fieldType, fieldName, isStaticInOuter)); 155 } 156 157 if (syntheticMethod != null) { 158 signature.setSyntheticMethod(methodSignature(syntheticMethod)); 159 } 160 161 if (getter != null) { 162 signature.setGetter(methodSignature(getter)); 163 } 164 if (setter != null) { 165 signature.setSetter(methodSignature(setter)); 166 } 167 168 return signature.build(); 169 } 170 171 @NotNull 172 public JavaProtoBuf.JavaFieldSignature fieldSignature(@NotNull Type type, @NotNull String name, boolean isStaticInOuter) { 173 JavaProtoBuf.JavaFieldSignature.Builder signature = JavaProtoBuf.JavaFieldSignature.newBuilder(); 174 signature.setName(nameTable.getSimpleNameIndex(Name.guess(name))); 175 signature.setType(type(type)); 176 if (isStaticInOuter) { 177 signature.setIsStaticInOuter(true); 178 } 179 return signature.build(); 180 } 181 182 @NotNull 183 public JavaProtoBuf.JavaType type(@NotNull Type givenType) { 184 JavaProtoBuf.JavaType.Builder builder = JavaProtoBuf.JavaType.newBuilder(); 185 186 int arrayDimension = 0; 187 Type type = givenType; 188 while (type.getSort() == Type.ARRAY) { 189 arrayDimension++; 190 type = type.getElementType(); 191 } 192 if (arrayDimension != 0) { 193 builder.setArrayDimension(arrayDimension); 194 } 195 196 if (type.getSort() == Type.OBJECT) { 197 FqName fqName = internalNameToFqName(type.getInternalName()); 198 builder.setClassFqName(nameTable.getFqNameIndex(fqName)); 199 } 200 else { 201 builder.setPrimitiveType(JavaProtoBuf.JavaType.PrimitiveType.valueOf(type.getSort())); 202 } 203 204 return builder.build(); 205 } 206 207 @NotNull 208 private static FqName internalNameToFqName(@NotNull String internalName) { 209 return FqName.fromSegments(Arrays.asList(internalName.split("/"))); 210 } 211 } 212 }