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.jet.descriptors.serialization.*; 023 import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPropertyDescriptor; 024 import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor; 025 import org.jetbrains.jet.lang.descriptors.*; 026 import org.jetbrains.jet.lang.resolve.kotlin.SignatureDeserializer; 027 import org.jetbrains.jet.lang.resolve.name.FqName; 028 import org.jetbrains.jet.lang.resolve.name.Name; 029 import org.jetbrains.org.objectweb.asm.Type; 030 import org.jetbrains.org.objectweb.asm.commons.Method; 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 StringTable stringTable 048 ) { 049 saveSignature(callable, proto, stringTable); 050 saveImplClassName(callable, proto, stringTable); 051 } 052 053 @Override 054 public void serializeValueParameter( 055 @NotNull ValueParameterDescriptor descriptor, 056 @NotNull ProtoBuf.Callable.ValueParameter.Builder proto, 057 @NotNull StringTable stringTable 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 StringTable stringTable 069 ) { 070 SignatureSerializer signatureSerializer = new SignatureSerializer(stringTable); 071 if (callable instanceof FunctionDescriptor) { 072 JavaProtoBuf.JavaMethodSignature signature; 073 if (callable instanceof DeserializedSimpleFunctionDescriptor) { 074 DeserializedSimpleFunctionDescriptor deserialized = (DeserializedSimpleFunctionDescriptor) callable; 075 signature = signatureSerializer.copyMethodSignature( 076 deserialized.getProto().getExtension(JavaProtoBuf.methodSignature), deserialized.getNameResolver()); 077 } 078 else { 079 Method method = bindings.get(METHOD_FOR_FUNCTION, (FunctionDescriptor) callable); 080 signature = method != null ? signatureSerializer.methodSignature(method) : null; 081 } 082 if (signature != null) { 083 proto.setExtension(JavaProtoBuf.methodSignature, signature); 084 } 085 } 086 else if (callable instanceof PropertyDescriptor) { 087 PropertyDescriptor property = (PropertyDescriptor) callable; 088 089 PropertyGetterDescriptor getter = property.getGetter(); 090 PropertySetterDescriptor setter = property.getSetter(); 091 Method getterMethod = getter == null ? null : bindings.get(METHOD_FOR_FUNCTION, getter); 092 Method setterMethod = setter == null ? null : bindings.get(METHOD_FOR_FUNCTION, setter); 093 094 Pair<Type, String> field = bindings.get(FIELD_FOR_PROPERTY, property); 095 Type fieldType; 096 String fieldName; 097 boolean isStaticInOuter; 098 Method syntheticMethod; 099 if (field != null) { 100 fieldType = field.first; 101 fieldName = field.second; 102 isStaticInOuter = bindings.get(STATIC_FIELD_IN_OUTER_CLASS, property); 103 syntheticMethod = null; 104 } 105 else { 106 fieldType = null; 107 fieldName = null; 108 isStaticInOuter = false; 109 syntheticMethod = bindings.get(SYNTHETIC_METHOD_FOR_PROPERTY, property); 110 } 111 112 JavaProtoBuf.JavaPropertySignature signature; 113 if (callable instanceof DeserializedPropertyDescriptor) { 114 DeserializedPropertyDescriptor deserializedCallable = (DeserializedPropertyDescriptor) callable; 115 signature = signatureSerializer.copyPropertySignature( 116 deserializedCallable.getProto().getExtension(JavaProtoBuf.propertySignature), 117 deserializedCallable.getNameResolver() 118 ); 119 } 120 else { 121 signature = signatureSerializer 122 .propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getterMethod, setterMethod); 123 } 124 proto.setExtension(JavaProtoBuf.propertySignature, signature); 125 } 126 } 127 128 private void saveImplClassName( 129 @NotNull CallableMemberDescriptor callable, 130 @NotNull ProtoBuf.Callable.Builder proto, 131 @NotNull StringTable stringTable 132 ) { 133 String name = bindings.get(IMPL_CLASS_NAME_FOR_CALLABLE, callable); 134 if (name != null) { 135 proto.setExtension(JavaProtoBuf.implClassName, stringTable.getSimpleNameIndex(Name.identifier(name))); 136 } 137 } 138 139 private static class SignatureSerializer { 140 private final StringTable stringTable; 141 142 public SignatureSerializer(@NotNull StringTable stringTable) { 143 this.stringTable = stringTable; 144 } 145 146 @NotNull 147 public JavaProtoBuf.JavaMethodSignature copyMethodSignature( 148 @NotNull JavaProtoBuf.JavaMethodSignature signature, 149 @NotNull NameResolver nameResolver 150 ) { 151 String method = new SignatureDeserializer(nameResolver).methodSignatureString(signature); 152 return methodSignature(getAsmMethod(method)); 153 } 154 155 @NotNull 156 public JavaProtoBuf.JavaMethodSignature methodSignature(@NotNull Method method) { 157 JavaProtoBuf.JavaMethodSignature.Builder signature = JavaProtoBuf.JavaMethodSignature.newBuilder(); 158 159 signature.setName(stringTable.getStringIndex(method.getName())); 160 161 signature.setReturnType(type(method.getReturnType())); 162 163 for (Type type : method.getArgumentTypes()) { 164 signature.addParameterType(type(type)); 165 } 166 167 return signature.build(); 168 } 169 170 @NotNull 171 public JavaProtoBuf.JavaPropertySignature copyPropertySignature( 172 @NotNull JavaProtoBuf.JavaPropertySignature signature, 173 @NotNull NameResolver nameResolver 174 ) { 175 Type fieldType; 176 String fieldName; 177 boolean isStaticInOuter; 178 SignatureDeserializer signatureDeserializer = new SignatureDeserializer(nameResolver); 179 if (signature.hasField()) { 180 JavaProtoBuf.JavaFieldSignature field = signature.getField(); 181 fieldType = Type.getType(signatureDeserializer.typeDescriptor(field.getType())); 182 fieldName = nameResolver.getName(field.getName()).asString(); 183 isStaticInOuter = field.getIsStaticInOuter(); 184 } 185 else { 186 fieldType = null; 187 fieldName = null; 188 isStaticInOuter = false; 189 } 190 191 Method syntheticMethod = signature.hasSyntheticMethod() 192 ? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getSyntheticMethod())) 193 : null; 194 195 Method getter = signature.hasGetter() ? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getGetter())) : null; 196 Method setter = signature.hasSetter() ? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getSetter())) : null; 197 198 return propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getter, setter); 199 } 200 201 @NotNull 202 public JavaProtoBuf.JavaPropertySignature propertySignature( 203 @Nullable Type fieldType, 204 @Nullable String fieldName, 205 boolean isStaticInOuter, 206 @Nullable Method syntheticMethod, 207 @Nullable Method getter, 208 @Nullable Method setter 209 ) { 210 JavaProtoBuf.JavaPropertySignature.Builder signature = JavaProtoBuf.JavaPropertySignature.newBuilder(); 211 212 if (fieldType != null) { 213 assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldType; 214 signature.setField(fieldSignature(fieldType, fieldName, isStaticInOuter)); 215 } 216 217 if (syntheticMethod != null) { 218 signature.setSyntheticMethod(methodSignature(syntheticMethod)); 219 } 220 221 if (getter != null) { 222 signature.setGetter(methodSignature(getter)); 223 } 224 if (setter != null) { 225 signature.setSetter(methodSignature(setter)); 226 } 227 228 return signature.build(); 229 } 230 231 @NotNull 232 public JavaProtoBuf.JavaFieldSignature fieldSignature(@NotNull Type type, @NotNull String name, boolean isStaticInOuter) { 233 JavaProtoBuf.JavaFieldSignature.Builder signature = JavaProtoBuf.JavaFieldSignature.newBuilder(); 234 signature.setName(stringTable.getStringIndex(name)); 235 signature.setType(type(type)); 236 if (isStaticInOuter) { 237 signature.setIsStaticInOuter(true); 238 } 239 return signature.build(); 240 } 241 242 @NotNull 243 public JavaProtoBuf.JavaType type(@NotNull Type givenType) { 244 JavaProtoBuf.JavaType.Builder builder = JavaProtoBuf.JavaType.newBuilder(); 245 246 int arrayDimension = 0; 247 Type type = givenType; 248 while (type.getSort() == Type.ARRAY) { 249 arrayDimension++; 250 type = type.getElementType(); 251 } 252 if (arrayDimension != 0) { 253 builder.setArrayDimension(arrayDimension); 254 } 255 256 if (type.getSort() == Type.OBJECT) { 257 FqName fqName = internalNameToFqName(type.getInternalName()); 258 builder.setClassFqName(stringTable.getFqNameIndex(fqName)); 259 } 260 else { 261 builder.setPrimitiveType(JavaProtoBuf.JavaType.PrimitiveType.valueOf(type.getSort())); 262 } 263 264 return builder.build(); 265 } 266 267 @NotNull 268 private static FqName internalNameToFqName(@NotNull String internalName) { 269 return FqName.fromSegments(Arrays.asList(internalName.split("/"))); 270 } 271 } 272 273 @NotNull 274 private static Method getAsmMethod(@NotNull String nameAndDesc) { 275 int indexOf = nameAndDesc.indexOf('('); 276 return new Method(nameAndDesc.substring(0, indexOf), nameAndDesc.substring(indexOf)); 277 } 278 }