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