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 return KotlinBuiltIns.isDeprecated(descriptor) 292 ? ACC_DEPRECATED 293 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 294 } 295 else if (KotlinBuiltIns.isDeprecated(descriptor)) { 296 return ACC_DEPRECATED; 297 } 298 return 0; 299 } 300 301 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 302 if (!functionDescriptor.getValueParameters().isEmpty() 303 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 304 .getVarargElementType() != null) { 305 return ACC_VARARGS; 306 } 307 return 0; 308 } 309 310 @Nullable 311 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 312 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 313 if (isInterface(containingDeclaration)) { 314 return ACC_PUBLIC; 315 } 316 317 Visibility memberVisibility = memberDescriptor.getVisibility(); 318 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 319 return ACC_PUBLIC; 320 } 321 322 if (isEnumEntry(memberDescriptor)) { 323 return NO_FLAG_PACKAGE_PRIVATE; 324 } 325 326 if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) { 327 return NO_FLAG_PACKAGE_PRIVATE; 328 } 329 330 if (memberDescriptor instanceof SyntheticJavaPropertyDescriptor) { 331 return getVisibilityAccessFlag(((SyntheticJavaPropertyDescriptor) memberDescriptor).getGetMethod()); 332 } 333 if (memberDescriptor instanceof PropertyAccessorDescriptor) { 334 PropertyDescriptor property = ((PropertyAccessorDescriptor) memberDescriptor).getCorrespondingProperty(); 335 if (property instanceof SyntheticJavaPropertyDescriptor) { 336 FunctionDescriptor method = memberDescriptor == property.getGetter() 337 ? ((SyntheticJavaPropertyDescriptor) property).getGetMethod() 338 : ((SyntheticJavaPropertyDescriptor) property).getSetMethod(); 339 assert method != null : "No get/set method in SyntheticJavaPropertyDescriptor: " + property; 340 return getVisibilityAccessFlag(method); 341 } 342 } 343 344 if (memberDescriptor instanceof CallableDescriptor && memberVisibility == Visibilities.PROTECTED) { 345 for (CallableDescriptor overridden : DescriptorUtils.getAllOverriddenDescriptors((CallableDescriptor) memberDescriptor)) { 346 if (isInterface(overridden.getContainingDeclaration())) { 347 return ACC_PUBLIC; 348 } 349 } 350 } 351 352 if (!Visibilities.isPrivate(memberVisibility)) { 353 return null; 354 } 355 356 // the following code is only for PRIVATE visibility of member 357 if (memberDescriptor instanceof ConstructorDescriptor) { 358 if (isNonCompanionObject(containingDeclaration) || isEnumEntry(containingDeclaration)) { 359 return NO_FLAG_PACKAGE_PRIVATE; 360 } 361 if (isEnumClass(containingDeclaration)) { 362 //TODO: should be ACC_PRIVATE 363 // see http://youtrack.jetbrains.com/issue/KT-2680 364 return ACC_PROTECTED; 365 } 366 } 367 368 if (containingDeclaration instanceof PackageFragmentDescriptor) { 369 return ACC_PUBLIC; 370 } 371 return null; 372 } 373 374 public static Type stringValueOfType(Type type) { 375 int sort = type.getSort(); 376 return sort == Type.OBJECT || sort == Type.ARRAY 377 ? OBJECT_TYPE 378 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 379 } 380 381 private static Type stringBuilderAppendType(Type type) { 382 switch (type.getSort()) { 383 case Type.OBJECT: 384 return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : OBJECT_TYPE; 385 case Type.ARRAY: 386 return OBJECT_TYPE; 387 case Type.BYTE: 388 case Type.SHORT: 389 return Type.INT_TYPE; 390 default: 391 return type; 392 } 393 } 394 395 public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) { 396 v.anew(Type.getObjectType(exception)); 397 v.dup(); 398 if (message != null) { 399 v.aconst(message); 400 v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false); 401 } 402 else { 403 v.invokespecial(exception, "<init>", "()V", false); 404 } 405 v.athrow(); 406 } 407 408 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 409 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>(); 410 411 ClassifierDescriptor captureThis = closure.getCaptureThis(); 412 if (captureThis != null) { 413 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis))); 414 } 415 416 JetType captureReceiverType = closure.getCaptureReceiverType(); 417 if (captureReceiverType != null) { 418 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType))); 419 } 420 421 allFields.addAll(closure.getRecordedFields()); 422 genClosureFields(allFields, v); 423 } 424 425 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) { 426 //noinspection PointlessBitwiseExpression 427 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 428 for (Pair<String, Type> field : allFields) { 429 builder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null); 430 } 431 } 432 433 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) { 434 List<FieldInfo> result = new ArrayList<FieldInfo>(); 435 for (Pair<String, Type> field : allFields) { 436 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); 437 } 438 return result; 439 } 440 441 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 442 assert !info.isStatic(); 443 Type fieldType = info.getFieldType(); 444 iv.load(0, info.getOwnerType());//this 445 iv.load(index, fieldType); //param 446 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 447 index += fieldType.getSize(); 448 return index; 449 } 450 451 public static void genStringBuilderConstructor(InstructionAdapter v) { 452 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 453 v.dup(); 454 v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false); 455 } 456 457 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 458 type = stringBuilderAppendType(type); 459 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false); 460 } 461 462 public static StackValue genToString(final StackValue receiver, final Type receiverType) { 463 return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() { 464 @Override 465 public Unit invoke(InstructionAdapter v) { 466 Type type = stringValueOfType(receiverType); 467 receiver.put(type, v); 468 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false); 469 return null; 470 } 471 }); 472 } 473 474 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 475 if (type.getSort() == Type.ARRAY) { 476 Type elementType = correctElementType(type); 477 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 478 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false); 479 } 480 else { 481 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false); 482 } 483 } 484 else if (type.getSort() == Type.OBJECT) { 485 iv.invokevirtual("java/lang/Object", "hashCode", "()I", false); 486 } 487 else if (type.getSort() == Type.LONG) { 488 genLongHashCode(mv, iv); 489 } 490 else if (type.getSort() == Type.DOUBLE) { 491 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false); 492 genLongHashCode(mv, iv); 493 } 494 else if (type.getSort() == Type.FLOAT) { 495 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false); 496 } 497 else if (type.getSort() == Type.BOOLEAN) { 498 Label end = new Label(); 499 iv.dup(); 500 iv.ifeq(end); 501 iv.pop(); 502 iv.iconst(1); 503 iv.mark(end); 504 } 505 else { // byte short char int 506 // do nothing 507 } 508 } 509 510 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 511 iv.dup2(); 512 iv.iconst(32); 513 iv.ushr(Type.LONG_TYPE); 514 iv.xor(Type.LONG_TYPE); 515 mv.visitInsn(L2I); 516 } 517 518 static void genInvertBoolean(InstructionAdapter v) { 519 v.iconst(1); 520 v.xor(Type.INT_TYPE); 521 } 522 523 @NotNull 524 public static StackValue genEqualsForExpressionsOnStack( 525 final @NotNull IElementType opToken, 526 final @NotNull StackValue left, 527 final @NotNull StackValue right 528 ) { 529 final Type leftType = left.type; 530 final Type rightType = right.type; 531 if (isPrimitive(leftType) && leftType == rightType) { 532 return StackValue.cmp(opToken, leftType, left, right); 533 } 534 535 return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() { 536 @Override 537 public Unit invoke(InstructionAdapter v) { 538 left.put(leftType, v); 539 right.put(rightType, v); 540 genAreEqualCall(v); 541 542 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 543 genInvertBoolean(v); 544 } 545 return Unit.INSTANCE$; 546 } 547 }); 548 } 549 550 public static void genAreEqualCall(InstructionAdapter v) { 551 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false); 552 } 553 554 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 555 if (expectedType == Type.LONG_TYPE) { 556 v.lconst(myDelta); 557 } 558 else if (expectedType == Type.FLOAT_TYPE) { 559 v.fconst(myDelta); 560 } 561 else if (expectedType == Type.DOUBLE_TYPE) { 562 v.dconst(myDelta); 563 } 564 else { 565 v.iconst(myDelta); 566 v.add(Type.INT_TYPE); 567 StackValue.coerce(Type.INT_TYPE, expectedType, v); 568 return; 569 } 570 v.add(expectedType); 571 } 572 573 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 574 if (stackTop.getSize() == 1) { 575 if (afterTop.getSize() == 1) { 576 v.swap(); 577 } 578 else { 579 v.dupX2(); 580 v.pop(); 581 } 582 } 583 else { 584 if (afterTop.getSize() == 1) { 585 v.dup2X1(); 586 } 587 else { 588 v.dup2X2(); 589 } 590 v.pop2(); 591 } 592 } 593 594 public static void genNotNullAssertionsForParameters( 595 @NotNull InstructionAdapter v, 596 @NotNull GenerationState state, 597 @NotNull FunctionDescriptor descriptor, 598 @NotNull FrameMap frameMap 599 ) { 600 if (!state.isParamAssertionsEnabled()) return; 601 602 // Private method is not accessible from other classes, no assertions needed 603 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 604 605 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 606 if (receiverParameter != null) { 607 genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver"); 608 } 609 610 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 611 genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString()); 612 } 613 } 614 615 private static void genParamAssertion( 616 @NotNull InstructionAdapter v, 617 @NotNull JetTypeMapper typeMapper, 618 @NotNull FrameMap frameMap, 619 @NotNull CallableDescriptor parameter, 620 @NotNull String name 621 ) { 622 JetType type = parameter.getReturnType(); 623 if (type == null || isNullableType(type)) return; 624 625 int index = frameMap.getIndex(parameter); 626 Type asmType = typeMapper.mapType(type); 627 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 628 v.load(index, asmType); 629 v.visitLdcInsn(name); 630 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull", 631 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 632 } 633 } 634 635 public static boolean genNotNullAssertionForField( 636 @NotNull InstructionAdapter v, 637 @NotNull GenerationState state, 638 @NotNull PropertyDescriptor descriptor 639 ) { 640 return genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 641 } 642 643 private static boolean genNotNullAssertion( 644 @NotNull InstructionAdapter v, 645 @NotNull GenerationState state, 646 @NotNull CallableDescriptor descriptor, 647 @NotNull String assertMethodToCall 648 ) { 649 // Assertions are generated elsewhere for platform types 650 if (JvmPackage.getPLATFORM_TYPES()) return false; 651 652 if (!state.isCallAssertionsEnabled()) return false; 653 654 if (!isDeclaredInJava(descriptor)) return false; 655 656 JetType type = descriptor.getReturnType(); 657 if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return false; 658 659 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 660 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 661 v.dup(); 662 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 663 v.visitLdcInsn(descriptor.getName().asString()); 664 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, assertMethodToCall, 665 "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false); 666 return true; 667 } 668 669 return false; 670 } 671 672 @NotNull 673 public static StackValue genNotNullAssertions( 674 @NotNull GenerationState state, 675 @NotNull final StackValue stackValue, 676 @Nullable final RuntimeAssertionInfo runtimeAssertionInfo 677 ) { 678 if (!state.isCallAssertionsEnabled()) return stackValue; 679 if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue; 680 681 return new StackValue(stackValue.type) { 682 683 @Override 684 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { 685 stackValue.put(type, v); 686 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 687 v.dup(); 688 v.visitLdcInsn(runtimeAssertionInfo.getMessage()); 689 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull", 690 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 691 } 692 } 693 }; 694 } 695 696 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 697 CallableDescriptor descriptor = callableDescriptor; 698 while (true) { 699 if (descriptor instanceof JavaCallableMemberDescriptor) { 700 return true; 701 } 702 CallableDescriptor original = descriptor.getOriginal(); 703 if (descriptor == original) break; 704 descriptor = original; 705 } 706 return false; 707 } 708 709 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 710 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 711 v.aconst(null); 712 } 713 else { 714 pushDefaultPrimitiveValueOnStack(type, v); 715 } 716 } 717 718 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 719 if (type.getSort() == Type.FLOAT) { 720 v.fconst(0); 721 } 722 else if (type.getSort() == Type.DOUBLE) { 723 v.dconst(0); 724 } 725 else if (type.getSort() == Type.LONG) { 726 v.lconst(0); 727 } 728 else { 729 v.iconst(0); 730 } 731 } 732 733 public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) { 734 if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 735 return false; 736 } 737 738 return isNonCompanionObject(propertyDescriptor.getContainingDeclaration()) || isPropertyWithBackingFieldInOuterClass(propertyDescriptor); 739 } 740 741 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 742 return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && 743 isCompanionObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration()); 744 } 745 746 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 747 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 748 if (isDelegate || isExtensionProperty) { 749 return ACC_PRIVATE; 750 } 751 else { 752 return areBothAccessorDefault(propertyDescriptor) 753 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) 754 : ACC_PRIVATE; 755 } 756 } 757 758 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 759 if (!propertyDescriptor.isVar()) { 760 return propertyDescriptor; 761 } 762 else { 763 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 764 } 765 } 766 767 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 768 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 769 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration(); 770 return !propertyDescriptor.isVar() 771 && !isExtensionProperty 772 && isCompanionObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration()) 773 && areBothAccessorDefault(propertyDescriptor) 774 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 775 } 776 777 public static boolean isCompanionObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor companionObject) { 778 DeclarationDescriptor containingClass = companionObject.getContainingDeclaration(); 779 return isCompanionObject(companionObject) && (isClass(containingClass) || isEnumClass(containingClass)); 780 } 781 782 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 783 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 784 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 785 } 786 787 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 788 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 789 } 790 791 public static Type comparisonOperandType(Type left, Type right) { 792 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 793 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 794 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 795 return Type.INT_TYPE; 796 } 797 798 @NotNull 799 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 800 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) { 801 return Type.INT_TYPE; 802 } 803 return expectedType; 804 } 805 806 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) { 807 if (type.getSize() == 2) { 808 v.visitInsn(Opcodes.POP2); 809 } 810 else { 811 v.visitInsn(Opcodes.POP); 812 } 813 } 814 815 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 816 int size = type.getSize(); 817 if (size == 2) { 818 v.dup2(); 819 } 820 else if (size == 1) { 821 v.dup(); 822 } 823 else { 824 throw new UnsupportedOperationException(); 825 } 826 } 827 828 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 829 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 830 JvmCodegenUtil.writeAbiVersion(av); 831 av.visitEnum( 832 JvmAnnotationNames.KIND_FIELD_NAME, 833 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 834 kind.toString() 835 ); 836 av.visitEnd(); 837 } 838 839 @NotNull 840 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 841 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 842 } 843 844 @NotNull 845 public static String shortNameByAsmType(@NotNull Type type) { 846 String internalName = type.getInternalName(); 847 int lastSlash = internalName.lastIndexOf('/'); 848 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 849 } 850 851 @NotNull 852 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 853 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName)); 854 } 855 856 @NotNull 857 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 858 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName(); 859 } 860 861 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { 862 if (isPrimitive(type)) { 863 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); 864 } 865 else { 866 v.aconst(type); 867 } 868 } 869 870 public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) { 871 v.invokestatic(REFLECTION, "foreignKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false); 872 } 873 874 875 public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) { 876 v.invokestatic(REFLECTION, "foreignKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false); 877 } 878 879 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) { 880 OwnerKind kind = context.getContextKind(); 881 //Trait always should have this descriptor 882 return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1; 883 } 884 }