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