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.google.common.collect.ImmutableMap; 020 import com.google.common.collect.Sets; 021 import com.intellij.openapi.util.Pair; 022 import com.intellij.psi.tree.IElementType; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.jet.codegen.binding.CalculatedClosure; 026 import org.jetbrains.jet.codegen.binding.CodegenBinding; 027 import org.jetbrains.jet.codegen.context.CodegenContext; 028 import org.jetbrains.jet.codegen.state.GenerationState; 029 import org.jetbrains.jet.codegen.state.JetTypeMapper; 030 import org.jetbrains.jet.lang.descriptors.*; 031 import org.jetbrains.jet.lang.psi.JetFile; 032 import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; 033 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 034 import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage; 035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 036 import org.jetbrains.jet.lang.resolve.java.*; 037 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor; 038 import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils; 039 import org.jetbrains.jet.lang.resolve.name.FqName; 040 import org.jetbrains.jet.lang.types.JetType; 041 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 042 import org.jetbrains.jet.lexer.JetTokens; 043 import org.jetbrains.org.objectweb.asm.*; 044 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 045 import org.jetbrains.org.objectweb.asm.commons.Method; 046 047 import java.util.ArrayList; 048 import java.util.List; 049 import java.util.Map; 050 import java.util.Set; 051 052 import static org.jetbrains.jet.codegen.JvmCodegenUtil.isInterface; 053 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; 054 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; 055 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType; 056 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; 057 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; 058 import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; 059 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive; 060 import static org.jetbrains.jet.lang.types.TypeUtils.isNullableType; 061 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 062 063 public class AsmUtil { 064 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( 065 KotlinBuiltIns.getInstance().getByte(), 066 KotlinBuiltIns.getInstance().getShort(), 067 KotlinBuiltIns.getInstance().getInt(), 068 KotlinBuiltIns.getInstance().getLong(), 069 KotlinBuiltIns.getInstance().getFloat(), 070 KotlinBuiltIns.getInstance().getDouble(), 071 KotlinBuiltIns.getInstance().getChar() 072 ); 073 074 private static final Set<Type> STRING_BUILDER_OBJECT_APPEND_ARG_TYPES = Sets.newHashSet( 075 getType(String.class), 076 getType(StringBuffer.class), 077 getType(CharSequence.class) 078 ); 079 080 private static final int NO_FLAG_LOCAL = 0; 081 public static final int NO_FLAG_PACKAGE_PRIVATE = 0; 082 083 @NotNull 084 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder() 085 .put(Visibilities.PRIVATE, ACC_PRIVATE) 086 .put(Visibilities.PROTECTED, ACC_PROTECTED) 087 .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED) 088 .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED) 089 .put(Visibilities.PUBLIC, ACC_PUBLIC) 090 .put(Visibilities.INTERNAL, ACC_PUBLIC) 091 .put(Visibilities.LOCAL, NO_FLAG_LOCAL) 092 .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE) 093 .build(); 094 095 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0"; 096 public static final String CAPTURED_THIS_FIELD = "this$0"; 097 098 private static final ImmutableMap<Integer, JvmPrimitiveType> primitiveTypeByAsmSort; 099 private static final ImmutableMap<Type, Type> primitiveTypeByBoxedType; 100 101 static { 102 ImmutableMap.Builder<Integer, JvmPrimitiveType> typeBySortBuilder = ImmutableMap.builder(); 103 ImmutableMap.Builder<Type, Type> typeByWrapperBuilder = ImmutableMap.builder(); 104 for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) { 105 Type asmType = asmTypeForPrimitive(primitiveType); 106 typeBySortBuilder.put(asmType.getSort(), primitiveType); 107 typeByWrapperBuilder.put(asmTypeByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()), asmType); 108 } 109 primitiveTypeByAsmSort = typeBySortBuilder.build(); 110 primitiveTypeByBoxedType = typeByWrapperBuilder.build(); 111 } 112 113 private AsmUtil() { 114 } 115 116 @NotNull 117 public static Type boxType(@NotNull Type type) { 118 JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort()); 119 return jvmPrimitiveType != null ? asmTypeByFqNameWithoutInnerClasses(jvmPrimitiveType.getWrapperFqName()) : type; 120 } 121 122 @NotNull 123 public static Type unboxType(@NotNull Type boxedType) { 124 Type primitiveType = primitiveTypeByBoxedType.get(boxedType); 125 if (primitiveType == null) { 126 throw new UnsupportedOperationException("Unboxing: " + boxedType); 127 } 128 return primitiveType; 129 } 130 131 public static boolean isIntPrimitive(Type type) { 132 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; 133 } 134 135 public static boolean isNumberPrimitive(Type type) { 136 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; 137 } 138 139 public static boolean isPrimitive(Type type) { 140 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY; 141 } 142 143 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) { 144 if (!(descriptor instanceof ClassDescriptor)) { 145 return false; 146 } 147 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor); 148 } 149 150 public static Type correctElementType(Type type) { 151 String internalName = type.getInternalName(); 152 assert internalName.charAt(0) == '['; 153 return Type.getType(internalName.substring(1)); 154 } 155 156 @NotNull 157 public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) { 158 return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes)); 159 } 160 161 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { 162 return (functionDescriptor.getModality() == Modality.ABSTRACT 163 || isInterface(functionDescriptor.getContainingDeclaration())) 164 && !isStaticMethod(kind, functionDescriptor); 165 } 166 167 public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) { 168 return isStaticKind(kind) || 169 JetTypeMapper.isAccessor(functionDescriptor) || 170 AnnotationsPackage.isPlatformStaticInObject(functionDescriptor); 171 } 172 173 public static boolean isStaticKind(OwnerKind kind) { 174 return kind == OwnerKind.PACKAGE || kind == OwnerKind.TRAIT_IMPL; 175 } 176 177 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { 178 int flags = getCommonCallableFlags(functionDescriptor); 179 180 for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) { 181 if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) { 182 flags |= flagAnnotation.getJvmFlag(); 183 } 184 } 185 186 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { 187 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); 188 if (!(containingDeclaration instanceof ClassDescriptor) || 189 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { 190 flags |= ACC_FINAL; 191 } 192 } 193 194 if (isStaticMethod(kind, functionDescriptor)) { 195 flags |= ACC_STATIC; 196 } 197 198 if (isAbstractMethod(functionDescriptor, kind)) { 199 flags |= ACC_ABSTRACT; 200 } 201 202 if (JetTypeMapper.isAccessor(functionDescriptor)) { 203 flags |= ACC_SYNTHETIC; 204 } 205 206 return flags; 207 } 208 209 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) { 210 int flags = getVisibilityAccessFlag(functionDescriptor); 211 flags |= getVarargsFlag(functionDescriptor); 212 flags |= getDeprecatedAccessFlag(functionDescriptor); 213 return flags; 214 } 215 216 //TODO: move mapping logic to front-end java 217 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) { 218 Integer specialCase = specialCaseVisibility(descriptor); 219 if (specialCase != null) { 220 return specialCase; 221 } 222 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility()); 223 if (defaultMapping == null) { 224 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend: " + descriptor); 225 } 226 return defaultMapping; 227 } 228 229 /* 230 Use this method to get visibility flag for class to define it in byte code (v.defineClass method). 231 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) 232 Classes in byte code should be public or package private 233 */ 234 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) { 235 if (DescriptorUtils.isTopLevelDeclaration(descriptor) || 236 descriptor.getVisibility() == Visibilities.PUBLIC || 237 descriptor.getVisibility() == Visibilities.INTERNAL) { 238 return ACC_PUBLIC; 239 } 240 return NO_FLAG_PACKAGE_PRIVATE; 241 } 242 243 public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) { 244 if (isDeclarationInsideInlineFunction(descriptor)) { 245 return ACC_PUBLIC; 246 } 247 return NO_FLAG_PACKAGE_PRIVATE; 248 } 249 250 private static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) { 251 //NB: constructor context couldn't be inline 252 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration(); 253 if (parentDeclaration instanceof SimpleFunctionDescriptor && 254 ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) { 255 return true; 256 } 257 return false; 258 } 259 260 public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) { 261 return getVisibilityAccessFlag(innerClass) | 262 innerAccessFlagsForModalityAndKind(innerClass) | 263 (innerClass.isInner() ? 0 : ACC_STATIC); 264 } 265 266 private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) { 267 switch (innerClass.getKind()) { 268 case TRAIT: 269 return ACC_ABSTRACT | ACC_INTERFACE; 270 case ENUM_CLASS: 271 return ACC_FINAL | ACC_ENUM; 272 case ANNOTATION_CLASS: 273 return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE; 274 default: 275 if (innerClass.getModality() == Modality.FINAL) { 276 return ACC_FINAL; 277 } 278 else if (innerClass.getModality() == Modality.ABSTRACT) { 279 return ACC_ABSTRACT; 280 } 281 } 282 return 0; 283 } 284 285 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { 286 if (descriptor instanceof PropertyAccessorDescriptor) { 287 return KotlinBuiltIns.getInstance().isDeprecated(descriptor) 288 ? ACC_DEPRECATED 289 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 290 } 291 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) { 292 return ACC_DEPRECATED; 293 } 294 return 0; 295 } 296 297 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 298 if (!functionDescriptor.getValueParameters().isEmpty() 299 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 300 .getVarargElementType() != null) { 301 return ACC_VARARGS; 302 } 303 return 0; 304 } 305 306 @Nullable 307 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 308 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 309 if (isInterface(containingDeclaration)) { 310 return ACC_PUBLIC; 311 } 312 Visibility memberVisibility = memberDescriptor.getVisibility(); 313 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 314 return ACC_PUBLIC; 315 } 316 if (isEnumEntry(memberDescriptor)) { 317 return NO_FLAG_PACKAGE_PRIVATE; 318 } 319 if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) { 320 return NO_FLAG_PACKAGE_PRIVATE; 321 } 322 if (memberVisibility != Visibilities.PRIVATE) { 323 return null; 324 } 325 // the following code is only for PRIVATE visibility of member 326 if (memberDescriptor instanceof ConstructorDescriptor) { 327 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 328 if (kind == ClassKind.OBJECT || kind == ClassKind.ENUM_ENTRY) { 329 return NO_FLAG_PACKAGE_PRIVATE; 330 } 331 if (kind == ClassKind.ENUM_CLASS) { 332 //TODO: should be ACC_PRIVATE 333 // see http://youtrack.jetbrains.com/issue/KT-2680 334 return ACC_PROTECTED; 335 } 336 } 337 if (containingDeclaration instanceof PackageFragmentDescriptor) { 338 return ACC_PUBLIC; 339 } 340 return null; 341 } 342 343 private static Type stringValueOfType(Type type) { 344 int sort = type.getSort(); 345 return sort == Type.OBJECT || sort == Type.ARRAY 346 ? AsmTypeConstants.OBJECT_TYPE 347 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 348 } 349 350 private static Type stringBuilderAppendType(Type type) { 351 switch (type.getSort()) { 352 case Type.OBJECT: 353 return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : AsmTypeConstants.OBJECT_TYPE; 354 case Type.ARRAY: 355 return AsmTypeConstants.OBJECT_TYPE; 356 case Type.BYTE: 357 case Type.SHORT: 358 return Type.INT_TYPE; 359 default: 360 return type; 361 } 362 } 363 364 public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) { 365 v.anew(Type.getObjectType(exception)); 366 v.dup(); 367 if (message != null) { 368 v.aconst(message); 369 v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false); 370 } 371 else { 372 v.invokespecial(exception, "<init>", "()V", false); 373 } 374 v.athrow(); 375 } 376 377 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 378 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>(); 379 380 ClassifierDescriptor captureThis = closure.getCaptureThis(); 381 if (captureThis != null) { 382 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis))); 383 } 384 385 JetType captureReceiverType = closure.getCaptureReceiverType(); 386 if (captureReceiverType != null) { 387 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType))); 388 } 389 390 allFields.addAll(closure.getRecordedFields()); 391 genClosureFields(allFields, v); 392 } 393 394 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) { 395 //noinspection PointlessBitwiseExpression 396 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 397 for (Pair<String, Type> field : allFields) { 398 builder.newField(NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null); 399 } 400 } 401 402 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) { 403 List<FieldInfo> result = new ArrayList<FieldInfo>(); 404 for (Pair<String, Type> field : allFields) { 405 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); 406 } 407 return result; 408 } 409 410 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 411 assert !info.isStatic(); 412 Type fieldType = info.getFieldType(); 413 iv.load(0, info.getOwnerType());//this 414 iv.load(index, fieldType); //param 415 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 416 index += fieldType.getSize(); 417 return index; 418 } 419 420 public static void genStringBuilderConstructor(InstructionAdapter v) { 421 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 422 v.dup(); 423 v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false); 424 } 425 426 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 427 type = stringBuilderAppendType(type); 428 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false); 429 } 430 431 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) { 432 Type type = stringValueOfType(receiverType); 433 receiver.put(type, v); 434 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false); 435 return StackValue.onStack(JAVA_STRING_TYPE); 436 } 437 438 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 439 if (type.getSort() == Type.ARRAY) { 440 Type elementType = correctElementType(type); 441 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 442 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false); 443 } 444 else { 445 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false); 446 } 447 } 448 else if (type.getSort() == Type.OBJECT) { 449 iv.invokevirtual("java/lang/Object", "hashCode", "()I", false); 450 } 451 else if (type.getSort() == Type.LONG) { 452 genLongHashCode(mv, iv); 453 } 454 else if (type.getSort() == Type.DOUBLE) { 455 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false); 456 genLongHashCode(mv, iv); 457 } 458 else if (type.getSort() == Type.FLOAT) { 459 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false); 460 } 461 else if (type.getSort() == Type.BOOLEAN) { 462 Label end = new Label(); 463 iv.dup(); 464 iv.ifeq(end); 465 iv.pop(); 466 iv.iconst(1); 467 iv.mark(end); 468 } 469 else { // byte short char int 470 // do nothing 471 } 472 } 473 474 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 475 iv.dup2(); 476 iv.iconst(32); 477 iv.ushr(Type.LONG_TYPE); 478 iv.xor(Type.LONG_TYPE); 479 mv.visitInsn(L2I); 480 } 481 482 static void genInvertBoolean(InstructionAdapter v) { 483 v.iconst(1); 484 v.xor(Type.INT_TYPE); 485 } 486 487 public static StackValue genEqualsForExpressionsOnStack( 488 InstructionAdapter v, 489 IElementType opToken, 490 Type leftType, 491 Type rightType 492 ) { 493 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) { 494 return StackValue.cmp(opToken, leftType); 495 } 496 else { 497 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 498 return StackValue.cmp(opToken, leftType); 499 } 500 else { 501 v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false); 502 503 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 504 genInvertBoolean(v); 505 } 506 507 return StackValue.onStack(Type.BOOLEAN_TYPE); 508 } 509 } 510 } 511 512 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 513 if (expectedType == Type.LONG_TYPE) { 514 v.lconst(myDelta); 515 } 516 else if (expectedType == Type.FLOAT_TYPE) { 517 v.fconst(myDelta); 518 } 519 else if (expectedType == Type.DOUBLE_TYPE) { 520 v.dconst(myDelta); 521 } 522 else { 523 v.iconst(myDelta); 524 v.add(Type.INT_TYPE); 525 StackValue.coerce(Type.INT_TYPE, expectedType, v); 526 return; 527 } 528 v.add(expectedType); 529 } 530 531 public static Type genNegate(Type expectedType, InstructionAdapter v) { 532 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) { 533 expectedType = Type.INT_TYPE; 534 } 535 v.neg(expectedType); 536 return expectedType; 537 } 538 539 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 540 if (stackTop.getSize() == 1) { 541 if (afterTop.getSize() == 1) { 542 v.swap(); 543 } 544 else { 545 v.dupX2(); 546 v.pop(); 547 } 548 } 549 else { 550 if (afterTop.getSize() == 1) { 551 v.dup2X1(); 552 } 553 else { 554 v.dup2X2(); 555 } 556 v.pop2(); 557 } 558 } 559 560 public static void genNotNullAssertionsForParameters( 561 @NotNull InstructionAdapter v, 562 @NotNull GenerationState state, 563 @NotNull FunctionDescriptor descriptor, 564 @NotNull FrameMap frameMap 565 ) { 566 if (!state.isParamAssertionsEnabled()) return; 567 568 // Private method is not accessible from other classes, no assertions needed 569 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 570 571 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 572 JetType type = parameter.getReturnType(); 573 if (type == null || isNullableType(type)) continue; 574 575 int index = frameMap.getIndex(parameter); 576 Type asmType = state.getTypeMapper().mapType(type); 577 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 578 v.load(index, asmType); 579 v.visitLdcInsn(parameter.getName().asString()); 580 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", 581 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 582 } 583 } 584 } 585 586 public static void genNotNullAssertionForField( 587 @NotNull InstructionAdapter v, 588 @NotNull GenerationState state, 589 @NotNull PropertyDescriptor descriptor 590 ) { 591 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 592 } 593 594 public static void genNotNullAssertionForMethod( 595 @NotNull InstructionAdapter v, 596 @NotNull GenerationState state, 597 @NotNull ResolvedCall resolvedCall 598 ) { 599 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 600 if (descriptor instanceof ConstructorDescriptor) return; 601 602 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 603 } 604 605 private static void genNotNullAssertion( 606 @NotNull InstructionAdapter v, 607 @NotNull GenerationState state, 608 @NotNull CallableDescriptor descriptor, 609 @NotNull String assertMethodToCall 610 ) { 611 if (!state.isCallAssertionsEnabled()) return; 612 613 if (!isDeclaredInJava(descriptor)) return; 614 615 JetType type = descriptor.getReturnType(); 616 if (type == null || isNullableType(type)) return; 617 618 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 619 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 620 v.dup(); 621 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 622 v.visitLdcInsn(descriptor.getName().asString()); 623 v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall, 624 "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false); 625 } 626 } 627 628 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 629 CallableDescriptor descriptor = callableDescriptor; 630 while (true) { 631 if (descriptor instanceof JavaCallableMemberDescriptor) { 632 return true; 633 } 634 CallableDescriptor original = descriptor.getOriginal(); 635 if (descriptor == original) break; 636 descriptor = original; 637 } 638 return false; 639 } 640 641 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 642 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 643 v.aconst(null); 644 } 645 else { 646 pushDefaultPrimitiveValueOnStack(type, v); 647 } 648 } 649 650 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 651 if (type.getSort() == Type.FLOAT) { 652 v.fconst(0); 653 } 654 else if (type.getSort() == Type.DOUBLE) { 655 v.dconst(0); 656 } 657 else if (type.getSort() == Type.LONG) { 658 v.lconst(0); 659 } 660 else { 661 v.iconst(0); 662 } 663 } 664 665 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 666 return isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration()); 667 } 668 669 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 670 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 671 if (isDelegate || isExtensionProperty) { 672 return ACC_PRIVATE; 673 } 674 else { 675 return areBothAccessorDefault(propertyDescriptor) 676 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) 677 : ACC_PRIVATE; 678 } 679 } 680 681 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 682 if (!propertyDescriptor.isVar()) { 683 return propertyDescriptor; 684 } 685 else { 686 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 687 } 688 } 689 690 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 691 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 692 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration(); 693 return !propertyDescriptor.isVar() 694 && !isExtensionProperty 695 && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration()) 696 && areBothAccessorDefault(propertyDescriptor) 697 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 698 } 699 700 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 701 DeclarationDescriptor containingClass = classObject.getContainingDeclaration(); 702 return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass)); 703 } 704 705 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 706 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 707 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 708 } 709 710 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 711 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 712 } 713 714 public static Type comparisonOperandType(Type left, Type right) { 715 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 716 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 717 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 718 return Type.INT_TYPE; 719 } 720 721 @NotNull 722 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 723 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) { 724 return Type.INT_TYPE; 725 } 726 return expectedType; 727 } 728 729 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) { 730 if (type.getSize() == 2) { 731 v.visitInsn(Opcodes.POP2); 732 } 733 else { 734 v.visitInsn(Opcodes.POP); 735 } 736 } 737 738 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 739 if (type.getSize() == 2) { 740 v.dup2(); 741 } 742 else { 743 v.dup(); 744 } 745 } 746 747 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 748 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 749 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 750 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), 751 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 752 kind.toString()); 753 av.visitEnd(); 754 } 755 756 @NotNull 757 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 758 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 759 } 760 761 @NotNull 762 public static String shortNameByAsmType(@NotNull Type type) { 763 String internalName = type.getInternalName(); 764 int lastSlash = internalName.lastIndexOf('/'); 765 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 766 } 767 768 @NotNull 769 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 770 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName)); 771 } 772 773 @NotNull 774 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 775 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName(); 776 } 777 778 public static void writeOuterClassAndEnclosingMethod( 779 @NotNull ClassDescriptor descriptor, 780 @NotNull DeclarationDescriptor originalDescriptor, 781 @NotNull JetTypeMapper typeMapper, 782 @NotNull ClassBuilder v 783 ) { 784 String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper); 785 FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class); 786 787 if (function != null) { 788 Method method = typeMapper.mapSignature(function).getAsmMethod(); 789 v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor()); 790 } 791 else { 792 v.visitOuterClass(outerClassName, null, null); 793 } 794 } 795 796 @NotNull 797 private static String getOuterClassName( 798 @NotNull ClassDescriptor classDescriptor, 799 @NotNull DeclarationDescriptor originalDescriptor, 800 @NotNull JetTypeMapper typeMapper 801 ) { 802 DeclarationDescriptor container = classDescriptor.getContainingDeclaration(); 803 while (container != null) { 804 if (container instanceof ClassDescriptor) { 805 return typeMapper.mapClass((ClassDescriptor) container).getInternalName(); 806 } 807 else if (CodegenBinding.isLocalFunOrLambda(container)) { 808 ClassDescriptor descriptor = 809 CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container); 810 return typeMapper.mapClass(descriptor).getInternalName(); 811 } 812 813 container = container.getContainingDeclaration(); 814 } 815 816 JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor); 817 assert containingFile != null : "Containing file should be present for " + classDescriptor; 818 return PackagePartClassUtils.getPackagePartInternalName(containingFile); 819 } 820 821 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { 822 if (isPrimitive(type)) { 823 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); 824 } 825 else { 826 v.aconst(type); 827 } 828 } 829 830 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) { 831 OwnerKind kind = context.getContextKind(); 832 //Trait always should have this descriptor 833 return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1; 834 } 835 }