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