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 }