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