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.signature;
018
019 import com.intellij.util.containers.Stack;
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.asm4.signature.SignatureVisitor;
025 import org.jetbrains.asm4.signature.SignatureWriter;
026 import org.jetbrains.asm4.util.CheckSignatureAdapter;
027 import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
028 import org.jetbrains.jet.lang.resolve.java.JetSignatureUtils;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lang.types.Variance;
031 import org.jetbrains.jet.rt.signature.JetSignatureAdapter;
032 import org.jetbrains.jet.rt.signature.JetSignatureReader;
033 import org.jetbrains.jet.rt.signature.JetSignatureVariance;
034 import org.jetbrains.jet.rt.signature.JetSignatureWriter;
035
036 import java.util.ArrayList;
037 import java.util.List;
038
039
040 public class BothSignatureWriter {
041
042 private static final boolean DEBUG_SIGNATURE_WRITER = true;
043
044 public enum Mode {
045 METHOD(CheckSignatureAdapter.METHOD_SIGNATURE),
046 CLASS(CheckSignatureAdapter.CLASS_SIGNATURE),
047 TYPE(CheckSignatureAdapter.TYPE_SIGNATURE);
048
049 private final int asmType;
050
051 Mode(int asmType) {
052 this.asmType = asmType;
053 }
054 }
055
056 private enum State {
057 START,
058 TYPE_PARAMETERS,
059
060 PARAMETERS,
061 PARAMETER,
062 RETURN_TYPE,
063 METHOD_END,
064
065 FIELD,
066 FIELD_END,
067
068 SUPERS,
069 CLASS_END,
070 }
071
072 private final SignatureWriter signatureWriter = new SignatureWriter();
073 private final SignatureVisitor signatureVisitor;
074
075 private JetSignatureWriter jetSignatureWriter;
076
077 private String kotlinClassParameters;
078 private String kotlinClassSignature;
079
080 private final List<JvmMethodParameterSignature> kotlinParameterTypes = new ArrayList<JvmMethodParameterSignature>();
081 private String kotlinReturnType;
082
083 private int jvmCurrentTypeArrayLevel;
084 private Type jvmCurrentType;
085 private Type jvmReturnType;
086
087 private JvmMethodParameterKind currentParameterKind;
088
089 private final Mode mode;
090 private final boolean needGenerics;
091
092 private State state = State.START;
093
094 private boolean generic = false;
095
096 public BothSignatureWriter(Mode mode, boolean needGenerics) {
097 this.mode = mode;
098 this.needGenerics = needGenerics;
099
100 if (DEBUG_SIGNATURE_WRITER) {
101 signatureVisitor = new CheckSignatureAdapter(mode.asmType, signatureWriter);
102 }
103 else {
104 signatureVisitor = signatureWriter;
105 }
106 }
107
108 // TODO: ignore when debugging is disabled
109 private final Stack<SignatureVisitor> visitors = new Stack<SignatureVisitor>();
110
111 private void push(SignatureVisitor visitor) {
112 visitors.push(visitor);
113 }
114
115 private void pop() {
116 visitors.pop();
117 }
118
119
120 private SignatureVisitor signatureVisitor() {
121 return !visitors.isEmpty() ? visitors.peek() : signatureVisitor;
122 }
123
124 private void checkTopLevel() {
125 if (DEBUG_SIGNATURE_WRITER) {
126 if (!visitors.isEmpty()) {
127 throw new IllegalStateException();
128 }
129 }
130 }
131
132 private void checkMode(Mode mode) {
133 if (DEBUG_SIGNATURE_WRITER) {
134 if (mode != this.mode) {
135 throw new IllegalStateException();
136 }
137 }
138 }
139
140 private void checkState(State state) {
141 if (DEBUG_SIGNATURE_WRITER) {
142 if (state != this.state) {
143 throw new IllegalStateException();
144 }
145 if (jetSignatureWriter != null) {
146 throw new IllegalStateException();
147 }
148 checkTopLevel();
149 }
150 }
151
152 private void transitionState(State from, State to) {
153 checkState(from);
154 state = to;
155 }
156
157 public void writeAsmType(Type asmType, boolean nullable) {
158 writeAsmType(asmType, nullable, null);
159 }
160
161 /**
162 * Shortcut
163 */
164 public void writeAsmType(Type asmType, boolean nullable, @Nullable String kotlinTypeName) {
165 switch (asmType.getSort()) {
166 case Type.OBJECT:
167 writeClassBegin(asmType.getInternalName(), nullable, false, kotlinTypeName);
168 writeClassEnd();
169 return;
170 case Type.ARRAY:
171 writeArrayType(nullable, Variance.INVARIANT);
172 writeAsmType(asmType.getElementType(), false, kotlinTypeName);
173 writeArrayEnd();
174 return;
175 default:
176 String descriptor = asmType.getDescriptor();
177 if (descriptor.length() != 1) {
178 throw new IllegalStateException();
179 }
180 writeBaseType(descriptor.charAt(0), nullable);
181 }
182 }
183
184 private void writeBaseType(char c, boolean nullable) {
185 if (nullable) {
186 throw new IllegalStateException();
187 }
188 signatureVisitor().visitBaseType(c);
189 jetSignatureWriter.visitBaseType(c, nullable);
190 writeAsmType0(Type.getType(String.valueOf(c)));
191 }
192
193 public void writeNothing(boolean nullable) {
194 if (nullable) {
195 signatureVisitor().visitClassType("java/lang/Object");
196 signatureVisitor().visitEnd();
197 }
198 else {
199 signatureVisitor().visitBaseType('V');
200 }
201 jetSignatureWriter.visitClassType("jet/Nothing", nullable, false);
202 jetSignatureWriter.visitEnd();
203 if (nullable) {
204 writeAsmType0(AsmTypeConstants.OBJECT_TYPE);
205 }
206 else {
207 writeAsmType0(Type.VOID_TYPE);
208 }
209 }
210
211 private String makeArrayPrefix() {
212 StringBuilder sb = new StringBuilder();
213 for (int i = 0; i < jvmCurrentTypeArrayLevel; ++i) {
214 sb.append('[');
215 }
216 return sb.toString();
217 }
218
219 private void writeAsmType0(Type type) {
220 if (jvmCurrentType == null) {
221 jvmCurrentType = Type.getType(makeArrayPrefix() + type.getDescriptor());
222 }
223 }
224
225 public void writeClassBegin(String internalName, boolean nullable, boolean real) {
226 writeClassBegin(internalName, nullable, real, null);
227 }
228
229 public void writeClassBegin(String internalName, boolean nullable, boolean real, @Nullable String kotlinTypeName) {
230 signatureVisitor().visitClassType(internalName);
231 jetSignatureWriter.visitClassType(kotlinTypeName == null ? internalName : kotlinTypeName, nullable, real);
232 writeAsmType0(Type.getObjectType(internalName));
233 }
234
235 public void writeClassEnd() {
236 signatureVisitor().visitEnd();
237 jetSignatureWriter.visitEnd();
238 }
239
240 public void writeArrayType(boolean nullable, Variance projectionKind) {
241 push(signatureVisitor().visitArrayType());
242 jetSignatureWriter.visitArrayType(nullable, toJetSignatureVariance(projectionKind));
243 if (jvmCurrentType == null) {
244 ++jvmCurrentTypeArrayLevel;
245 }
246 }
247
248 public void writeArrayEnd() {
249 pop();
250 }
251
252 private static JetSignatureVariance toJetSignatureVariance(Variance variance) {
253 switch (variance) {
254 case INVARIANT:
255 return JetSignatureVariance.INVARIANT;
256 case IN_VARIANCE:
257 return JetSignatureVariance.IN;
258 case OUT_VARIANCE:
259 return JetSignatureVariance.OUT;
260 default:
261 throw new IllegalStateException();
262 }
263 }
264
265 public void writeTypeArgument(Variance projectionKindForKotlin, Variance projectionKindForJava) {
266 push(signatureVisitor().visitTypeArgument(
267 toJetSignatureVariance(projectionKindForJava).getChar()
268 ));
269
270 jetSignatureWriter.visitTypeArgument(toJetSignatureVariance(projectionKindForKotlin));
271 generic = true;
272 }
273
274 public void writeTypeArgumentEnd() {
275 pop();
276 }
277
278 public void writeTypeVariable(Name name, boolean nullable, Type asmType) {
279 signatureVisitor().visitTypeVariable(name.asString());
280 jetSignatureWriter.visitTypeVariable(name.asString(), nullable);
281 generic = true;
282 writeAsmType0(asmType);
283 }
284
285 public void writeFormalTypeParameter(String name, Variance variance, boolean reified) {
286 checkTopLevel();
287
288 signatureVisitor().visitFormalTypeParameter(name);
289 jetSignatureWriter.visitFormalTypeParameter(name, JetSignatureUtils.translateVariance(variance), reified);
290
291 generic = true;
292 }
293
294 public void writeFormalTypeParameterEnd() {
295 jetSignatureWriter.visitFormalTypeParameterEnd();
296 }
297
298 public void writeFormalTypeParametersStart() {
299 checkTopLevel();
300 transitionState(State.START, State.TYPE_PARAMETERS);
301 jetSignatureWriter = new JetSignatureWriter();
302 }
303
304 public void writeFormalTypeParametersEnd() {
305 jetSignatureWriter.visitSuperclass(); // just to call endFormals
306
307 kotlinClassParameters = jetSignatureWriter.toString();
308
309 jetSignatureWriter = null;
310
311 if (DEBUG_SIGNATURE_WRITER) {
312 new JetSignatureReader(kotlinClassParameters).acceptFormalTypeParametersOnly(new JetSignatureAdapter());
313 }
314
315 checkState(State.TYPE_PARAMETERS);
316 }
317
318 public void writeClassBound() {
319 push(signatureVisitor().visitClassBound());
320 jetSignatureWriter.visitClassBound();
321 }
322
323 public void writeClassBoundEnd() {
324 pop();
325 }
326
327 public void writeInterfaceBound() {
328 push(signatureVisitor().visitInterfaceBound());
329 jetSignatureWriter.visitInterfaceBound();
330 }
331
332 public void writeInterfaceBoundEnd() {
333 pop();
334 }
335
336 public void writeParametersStart() {
337 transitionState(State.TYPE_PARAMETERS, State.PARAMETERS);
338
339 // hacks
340 jvmCurrentType = null;
341 jvmCurrentTypeArrayLevel = 0;
342 }
343
344 public void writeParametersEnd() {
345 checkState(State.PARAMETERS);
346 }
347
348 public void writeFieldTypeStart() {
349 transitionState(State.START, State.FIELD);
350 jetSignatureWriter = new JetSignatureWriter();
351 }
352
353 public void writeFieldTypeEnd() {
354 jetSignatureWriter = null;
355 transitionState(State.FIELD, State.FIELD_END);
356 }
357
358 public void writeParameterType(JvmMethodParameterKind parameterKind) {
359 transitionState(State.PARAMETERS, State.PARAMETER);
360
361 // This magic mimics the behavior of javac that enum constructor have these synthetic parameters in erased signature, but doesn't
362 // have them in generic signature. IDEA relies on this behavior.
363 if (parameterKind == JvmMethodParameterKind.ENUM_NAME || parameterKind == JvmMethodParameterKind.ENUM_ORDINAL) {
364 generic = true;
365
366 // pushing dummy visitor, because we don't want these parameters to appear in generic JVM signature
367 push(new SignatureWriter());
368 }
369 else {
370 push(signatureVisitor().visitParameterType());
371 }
372
373 jetSignatureWriter = new JetSignatureWriter();
374 if (jvmCurrentType != null || jvmCurrentTypeArrayLevel != 0) {
375 throw new IllegalStateException();
376 }
377
378 if (currentParameterKind != null) {
379 throw new IllegalStateException();
380 }
381 this.currentParameterKind = parameterKind;
382
383 //jetSignatureWriter.visitParameterType();
384 }
385
386 public void writeParameterTypeEnd() {
387 pop();
388
389 if (jvmCurrentType == null) {
390 throw new IllegalStateException();
391 }
392
393 String signature = jetSignatureWriter.toString();
394 kotlinParameterTypes.add(new JvmMethodParameterSignature(jvmCurrentType, signature, currentParameterKind));
395
396 if (DEBUG_SIGNATURE_WRITER) {
397 new JetSignatureReader(signature).acceptTypeOnly(new JetSignatureAdapter());
398 }
399
400 currentParameterKind = null;
401 jvmCurrentType = null;
402 jvmCurrentTypeArrayLevel = 0;
403
404 jetSignatureWriter = null;
405 transitionState(State.PARAMETER, State.PARAMETERS);
406 }
407
408 public void writeReturnType() {
409 transitionState(State.PARAMETERS, State.RETURN_TYPE);
410
411 jetSignatureWriter = new JetSignatureWriter();
412
413 if (jvmCurrentType != null) {
414 throw new IllegalStateException();
415 }
416
417 push(signatureVisitor().visitReturnType());
418 //jetSignatureWriter.visitReturnType();
419 }
420
421 public void writeReturnTypeEnd() {
422 pop();
423
424 kotlinReturnType = jetSignatureWriter.toString();
425
426 if (jvmCurrentType == null) {
427 throw new IllegalStateException();
428 }
429
430 jvmReturnType = jvmCurrentType;
431 jvmCurrentType = null;
432 jvmCurrentTypeArrayLevel = 0;
433
434 if (DEBUG_SIGNATURE_WRITER) {
435 new JetSignatureReader(kotlinReturnType).acceptTypeOnly(new JetSignatureAdapter());
436 }
437
438 jetSignatureWriter = null;
439 transitionState(State.RETURN_TYPE, State.METHOD_END);
440 }
441
442 public void writeVoidReturn() {
443 writeReturnType();
444 writeAsmType(Type.VOID_TYPE, false);
445 writeReturnTypeEnd();
446 }
447
448 public void writeSupersStart() {
449 transitionState(State.TYPE_PARAMETERS, State.SUPERS);
450 jetSignatureWriter = new JetSignatureWriter();
451 }
452
453 public void writeSupersEnd() {
454 kotlinClassSignature = jetSignatureWriter.toString();
455 jetSignatureWriter = null;
456
457 if (DEBUG_SIGNATURE_WRITER) {
458 new JetSignatureReader(kotlinClassSignature).accept(new JetSignatureAdapter());
459 }
460
461 transitionState(State.SUPERS, State.CLASS_END);
462 }
463
464 public void writeSuperclass() {
465 push(signatureVisitor().visitSuperclass());
466 jetSignatureWriter.visitSuperclass();
467 }
468
469 public void writeSuperclassEnd() {
470 pop();
471 if (!visitors.isEmpty()) {
472 throw new IllegalStateException();
473 }
474 }
475
476 public void writeInterface() {
477 checkTopLevel();
478 checkMode(Mode.CLASS);
479
480 push(signatureVisitor().visitInterface());
481 jetSignatureWriter.visitInterface();
482 }
483
484 public void writeInterfaceEnd() {
485 pop();
486 if (!visitors.isEmpty()) {
487 throw new IllegalStateException();
488 }
489 }
490
491
492 @NotNull
493 protected Method makeAsmMethod(String name) {
494 List<Type> jvmParameterTypes = new ArrayList<Type>(kotlinParameterTypes.size());
495 for (JvmMethodParameterSignature p : kotlinParameterTypes) {
496 jvmParameterTypes.add(p.getAsmType());
497 }
498 return new Method(name, jvmReturnType, jvmParameterTypes.toArray(new Type[jvmParameterTypes.size()]));
499 }
500
501 @Nullable
502 public String makeJavaGenericSignature() {
503 if (state != State.METHOD_END && state != State.CLASS_END && state != State.FIELD_END) {
504 throw new IllegalStateException();
505 }
506 checkTopLevel();
507 return generic ? signatureWriter.toString() : null;
508 }
509
510 @NotNull
511 protected List<JvmMethodParameterSignature> makeKotlinParameterTypes() {
512 checkState(State.METHOD_END);
513 // TODO: return nulls if equal to #makeJavaString
514 return kotlinParameterTypes;
515 }
516
517 @NotNull
518 protected String makeKotlinReturnTypeSignature() {
519 checkState(State.METHOD_END);
520 return kotlinReturnType;
521 }
522
523 protected String makeKotlinMethodTypeParameters() {
524 checkState(State.METHOD_END);
525 return kotlinClassParameters;
526 }
527
528 @NotNull
529 public String makeKotlinClassSignature() {
530 checkState(State.CLASS_END);
531 if (kotlinClassParameters == null) {
532 throw new IllegalStateException();
533 }
534 if (kotlinClassSignature == null) {
535 throw new IllegalStateException();
536 }
537 return kotlinClassParameters + kotlinClassSignature;
538 }
539
540 @NotNull
541 public JvmMethodSignature makeJvmMethodSignature(String name) {
542 return new JvmMethodSignature(
543 makeAsmMethod(name),
544 needGenerics ? makeJavaGenericSignature() : null,
545 needGenerics ? makeKotlinMethodTypeParameters() : null,
546 makeKotlinParameterTypes(),
547 makeKotlinReturnTypeSignature(),
548 needGenerics
549 );
550 }
551
552 @NotNull
553 public JvmPropertyAccessorSignature makeJvmPropertyAccessorSignature(String name, boolean isGetter) {
554 return new JvmPropertyAccessorSignature(
555 makeAsmMethod(name),
556 needGenerics ? makeJavaGenericSignature() : null,
557 needGenerics ? makeKotlinMethodTypeParameters() : null,
558 makeKotlinParameterTypes(),
559 makeKotlinReturnTypeSignature(),
560 needGenerics,
561 isGetter
562 );
563 }
564 }
565