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 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 601 JetType type = parameter.getReturnType(); 602 if (type == null || isNullableType(type)) continue; 603 604 int index = frameMap.getIndex(parameter); 605 Type asmType = state.getTypeMapper().mapType(type); 606 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 607 v.load(index, asmType); 608 v.visitLdcInsn(parameter.getName().asString()); 609 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull", 610 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 611 } 612 } 613 } 614 615 public static void genNotNullAssertionForField( 616 @NotNull InstructionAdapter v, 617 @NotNull GenerationState state, 618 @NotNull PropertyDescriptor descriptor 619 ) { 620 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 621 } 622 623 public static void genNotNullAssertionForMethod( 624 @NotNull InstructionAdapter v, 625 @NotNull GenerationState state, 626 @NotNull ResolvedCall resolvedCall 627 ) { 628 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 629 if (descriptor instanceof ConstructorDescriptor) return; 630 631 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 632 } 633 634 private static void genNotNullAssertion( 635 @NotNull InstructionAdapter v, 636 @NotNull GenerationState state, 637 @NotNull CallableDescriptor descriptor, 638 @NotNull String assertMethodToCall 639 ) { 640 // Assertions are generated elsewhere for platform types 641 if (JvmPackage.getPLATFORM_TYPES()) return; 642 643 if (!state.isCallAssertionsEnabled()) return; 644 645 if (!isDeclaredInJava(descriptor)) return; 646 647 JetType type = descriptor.getReturnType(); 648 if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return; 649 650 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 651 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 652 v.dup(); 653 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 654 v.visitLdcInsn(descriptor.getName().asString()); 655 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, assertMethodToCall, 656 "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false); 657 } 658 } 659 660 @NotNull 661 public static StackValue genNotNullAssertions( 662 @NotNull GenerationState state, 663 @NotNull final StackValue stackValue, 664 @Nullable final Approximation.Info approximationInfo 665 ) { 666 if (!state.isCallAssertionsEnabled()) return stackValue; 667 if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue; 668 669 return new StackValue(stackValue.type) { 670 671 @Override 672 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { 673 stackValue.put(type, v); 674 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 675 v.dup(); 676 v.visitLdcInsn(approximationInfo.getMessage()); 677 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull", 678 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 679 } 680 } 681 }; 682 } 683 684 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 685 CallableDescriptor descriptor = callableDescriptor; 686 while (true) { 687 if (descriptor instanceof JavaCallableMemberDescriptor) { 688 return true; 689 } 690 CallableDescriptor original = descriptor.getOriginal(); 691 if (descriptor == original) break; 692 descriptor = original; 693 } 694 return false; 695 } 696 697 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 698 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 699 v.aconst(null); 700 } 701 else { 702 pushDefaultPrimitiveValueOnStack(type, v); 703 } 704 } 705 706 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 707 if (type.getSort() == Type.FLOAT) { 708 v.fconst(0); 709 } 710 else if (type.getSort() == Type.DOUBLE) { 711 v.dconst(0); 712 } 713 else if (type.getSort() == Type.LONG) { 714 v.lconst(0); 715 } 716 else { 717 v.iconst(0); 718 } 719 } 720 721 public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) { 722 if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 723 return false; 724 } 725 726 return isObject(propertyDescriptor.getContainingDeclaration()) || isPropertyWithBackingFieldInOuterClass(propertyDescriptor); 727 } 728 729 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 730 return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && 731 isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration()); 732 } 733 734 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 735 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 736 if (isDelegate || isExtensionProperty) { 737 return ACC_PRIVATE; 738 } 739 else { 740 return areBothAccessorDefault(propertyDescriptor) 741 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) 742 : ACC_PRIVATE; 743 } 744 } 745 746 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 747 if (!propertyDescriptor.isVar()) { 748 return propertyDescriptor; 749 } 750 else { 751 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 752 } 753 } 754 755 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 756 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 757 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration(); 758 return !propertyDescriptor.isVar() 759 && !isExtensionProperty 760 && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration()) 761 && areBothAccessorDefault(propertyDescriptor) 762 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 763 } 764 765 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 766 DeclarationDescriptor containingClass = classObject.getContainingDeclaration(); 767 return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass)); 768 } 769 770 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 771 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 772 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 773 } 774 775 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 776 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 777 } 778 779 public static Type comparisonOperandType(Type left, Type right) { 780 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 781 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 782 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 783 return Type.INT_TYPE; 784 } 785 786 @NotNull 787 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 788 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) { 789 return Type.INT_TYPE; 790 } 791 return expectedType; 792 } 793 794 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) { 795 if (type.getSize() == 2) { 796 v.visitInsn(Opcodes.POP2); 797 } 798 else { 799 v.visitInsn(Opcodes.POP); 800 } 801 } 802 803 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 804 int size = type.getSize(); 805 if (size == 2) { 806 v.dup2(); 807 } 808 else if (size == 1) { 809 v.dup(); 810 } 811 else { 812 throw new UnsupportedOperationException(); 813 } 814 } 815 816 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 817 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 818 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 819 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), 820 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 821 kind.toString()); 822 av.visitEnd(); 823 } 824 825 @NotNull 826 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 827 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 828 } 829 830 @NotNull 831 public static String shortNameByAsmType(@NotNull Type type) { 832 String internalName = type.getInternalName(); 833 int lastSlash = internalName.lastIndexOf('/'); 834 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 835 } 836 837 @NotNull 838 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 839 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName)); 840 } 841 842 @NotNull 843 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 844 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName(); 845 } 846 847 public static void writeOuterClassAndEnclosingMethod( 848 @NotNull ClassDescriptor descriptor, 849 @NotNull DeclarationDescriptor originalDescriptor, 850 @NotNull JetTypeMapper typeMapper, 851 @NotNull ClassBuilder v 852 ) { 853 String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper); 854 855 FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class); 856 while (function != null && JvmCodegenUtil.isLambdaWhichWillBeInlined(typeMapper.getBindingContext(), function)) { 857 function = DescriptorUtils.getParentOfType(function, FunctionDescriptor.class); 858 } 859 860 if (function != null) { 861 Method method = typeMapper.mapSignature(function).getAsmMethod(); 862 v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor()); 863 } 864 else { 865 v.visitOuterClass(outerClassName, null, null); 866 } 867 } 868 869 @NotNull 870 private static String getOuterClassName( 871 @NotNull ClassDescriptor classDescriptor, 872 @NotNull DeclarationDescriptor originalDescriptor, 873 @NotNull JetTypeMapper typeMapper 874 ) { 875 BindingContext bindingContext = typeMapper.getBindingContext(); 876 877 DeclarationDescriptor container = classDescriptor.getContainingDeclaration(); 878 while (container != null) { 879 if (container instanceof ClassDescriptor) { 880 return typeMapper.mapClass((ClassDescriptor) container).getInternalName(); 881 } 882 else if (CodegenBinding.isLocalFunOrLambda(container) && 883 !JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) { 884 return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) container).getInternalName(); 885 } 886 887 container = container.getContainingDeclaration(); 888 } 889 890 JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor); 891 assert containingFile != null : "Containing file should be present for " + classDescriptor; 892 return PackagePartClassUtils.getPackagePartInternalName(containingFile); 893 } 894 895 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { 896 if (isPrimitive(type)) { 897 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); 898 } 899 else { 900 v.aconst(type); 901 } 902 } 903 904 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) { 905 OwnerKind kind = context.getContextKind(); 906 //Trait always should have this descriptor 907 return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1; 908 } 909 }