001 /* 002 * Copyright 2010-2013 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.jet.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 org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.jet.codegen.binding.CalculatedClosure; 026 import org.jetbrains.jet.codegen.state.GenerationState; 027 import org.jetbrains.jet.codegen.state.JetTypeMapper; 028 import org.jetbrains.jet.lang.descriptors.*; 029 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 030 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 031 import org.jetbrains.jet.lang.resolve.java.*; 032 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor; 033 import org.jetbrains.jet.lang.resolve.name.FqName; 034 import org.jetbrains.jet.lang.types.JetType; 035 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 036 import org.jetbrains.jet.lexer.JetTokens; 037 import org.jetbrains.org.objectweb.asm.AnnotationVisitor; 038 import org.jetbrains.org.objectweb.asm.Label; 039 import org.jetbrains.org.objectweb.asm.MethodVisitor; 040 import org.jetbrains.org.objectweb.asm.Type; 041 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 042 043 import java.util.ArrayList; 044 import java.util.List; 045 import java.util.Map; 046 import java.util.Set; 047 048 import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; 049 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; 050 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; 051 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; 052 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; 053 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive; 054 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 055 056 public class AsmUtil { 057 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( 058 KotlinBuiltIns.getInstance().getByte(), 059 KotlinBuiltIns.getInstance().getShort(), 060 KotlinBuiltIns.getInstance().getInt(), 061 KotlinBuiltIns.getInstance().getLong(), 062 KotlinBuiltIns.getInstance().getFloat(), 063 KotlinBuiltIns.getInstance().getDouble(), 064 KotlinBuiltIns.getInstance().getChar() 065 ); 066 067 private static final int NO_FLAG_LOCAL = 0; 068 public static final int NO_FLAG_PACKAGE_PRIVATE = 0; 069 070 @NotNull 071 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder() 072 .put(Visibilities.PRIVATE, ACC_PRIVATE) 073 .put(Visibilities.PROTECTED, ACC_PROTECTED) 074 .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED) 075 .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED) 076 .put(Visibilities.PUBLIC, ACC_PUBLIC) 077 .put(Visibilities.INTERNAL, ACC_PUBLIC) 078 .put(Visibilities.LOCAL, NO_FLAG_LOCAL) 079 .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE) 080 .build(); 081 082 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0"; 083 public static final String CAPTURED_THIS_FIELD = "this$0"; 084 085 private static final ImmutableMap<Integer, JvmPrimitiveType> primitiveTypeByAsmSort; 086 private static final ImmutableMap<Type, Type> primitiveTypeByBoxedType; 087 088 static { 089 ImmutableMap.Builder<Integer, JvmPrimitiveType> typeBySortBuilder = ImmutableMap.builder(); 090 ImmutableMap.Builder<Type, Type> typeByWrapperBuilder = ImmutableMap.builder(); 091 for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) { 092 Type asmType = asmTypeForPrimitive(primitiveType); 093 typeBySortBuilder.put(asmType.getSort(), primitiveType); 094 typeByWrapperBuilder.put(asmTypeByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()), asmType); 095 } 096 primitiveTypeByAsmSort = typeBySortBuilder.build(); 097 primitiveTypeByBoxedType = typeByWrapperBuilder.build(); 098 } 099 100 private AsmUtil() { 101 } 102 103 @NotNull 104 public static Type boxType(@NotNull Type type) { 105 JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort()); 106 return jvmPrimitiveType != null ? asmTypeByFqNameWithoutInnerClasses(jvmPrimitiveType.getWrapperFqName()) : type; 107 } 108 109 @NotNull 110 public static Type unboxType(@NotNull Type boxedType) { 111 Type primitiveType = primitiveTypeByBoxedType.get(boxedType); 112 if (primitiveType == null) { 113 throw new UnsupportedOperationException("Unboxing: " + boxedType); 114 } 115 return primitiveType; 116 } 117 118 public static boolean isIntPrimitive(Type type) { 119 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; 120 } 121 122 public static boolean isNumberPrimitive(Type type) { 123 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; 124 } 125 126 public static boolean isPrimitive(Type type) { 127 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY; 128 } 129 130 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) { 131 if (!(descriptor instanceof ClassDescriptor)) { 132 return false; 133 } 134 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor); 135 } 136 137 public static Type correctElementType(Type type) { 138 String internalName = type.getInternalName(); 139 assert internalName.charAt(0) == '['; 140 return Type.getType(internalName.substring(1)); 141 } 142 143 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { 144 return (functionDescriptor.getModality() == Modality.ABSTRACT 145 || isInterface(functionDescriptor.getContainingDeclaration())) 146 && !isStaticMethod(kind, functionDescriptor); 147 } 148 149 public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) { 150 return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor); 151 } 152 153 public static boolean isStatic(OwnerKind kind) { 154 return kind == OwnerKind.PACKAGE || kind == OwnerKind.TRAIT_IMPL; 155 } 156 157 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { 158 int flags = getCommonCallableFlags(functionDescriptor); 159 160 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { 161 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); 162 if (!(containingDeclaration instanceof ClassDescriptor) || 163 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { 164 flags |= ACC_FINAL; 165 } 166 } 167 168 if (isStaticMethod(kind, functionDescriptor)) { 169 flags |= ACC_STATIC; 170 } 171 172 if (isAbstractMethod(functionDescriptor, kind)) { 173 flags |= ACC_ABSTRACT; 174 } 175 176 if (JetTypeMapper.isAccessor(functionDescriptor)) { 177 flags |= ACC_SYNTHETIC; 178 } 179 180 return flags; 181 } 182 183 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) { 184 int flags = getVisibilityAccessFlag(functionDescriptor); 185 flags |= getVarargsFlag(functionDescriptor); 186 flags |= getDeprecatedAccessFlag(functionDescriptor); 187 return flags; 188 } 189 190 //TODO: move mapping logic to front-end java 191 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) { 192 Integer specialCase = specialCaseVisibility(descriptor); 193 if (specialCase != null) { 194 return specialCase; 195 } 196 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility()); 197 if (defaultMapping == null) { 198 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend. Descriptor: " + descriptor); 199 } 200 return defaultMapping; 201 } 202 203 /* 204 Use this method to get visibility flag for class to define it in byte code (v.defineClass method). 205 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) 206 Classes in byte code should be public or package private 207 */ 208 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) { 209 if (DescriptorUtils.isTopLevelDeclaration(descriptor) || 210 descriptor.getVisibility() == Visibilities.PUBLIC || 211 descriptor.getVisibility() == Visibilities.INTERNAL) { 212 return ACC_PUBLIC; 213 } 214 return NO_FLAG_PACKAGE_PRIVATE; 215 } 216 217 218 public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) { 219 if (isDeclarationInsideInlineFunction(descriptor)) { 220 return ACC_PUBLIC; 221 } 222 return NO_FLAG_PACKAGE_PRIVATE; 223 } 224 225 public static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) { 226 //NB: constructor context couldn't be inline 227 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration(); 228 if (parentDeclaration instanceof SimpleFunctionDescriptor && 229 ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) { 230 return true; 231 } 232 return false; 233 } 234 235 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { 236 if (descriptor instanceof PropertyAccessorDescriptor) { 237 return KotlinBuiltIns.getInstance().isDeprecated(descriptor) 238 ? ACC_DEPRECATED 239 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 240 } 241 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) { 242 return ACC_DEPRECATED; 243 } 244 return 0; 245 } 246 247 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 248 if (!functionDescriptor.getValueParameters().isEmpty() 249 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 250 .getVarargElementType() != null) { 251 return ACC_VARARGS; 252 } 253 return 0; 254 } 255 256 @Nullable 257 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 258 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 259 if (isInterface(containingDeclaration)) { 260 return ACC_PUBLIC; 261 } 262 Visibility memberVisibility = memberDescriptor.getVisibility(); 263 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 264 return ACC_PUBLIC; 265 } 266 if (isEnumEntry(memberDescriptor)) { 267 return NO_FLAG_PACKAGE_PRIVATE; 268 } 269 if (memberVisibility != Visibilities.PRIVATE) { 270 return null; 271 } 272 // the following code is only for PRIVATE visibility of member 273 if (memberDescriptor instanceof ConstructorDescriptor) { 274 if (isAnonymousObject(containingDeclaration)) { 275 return NO_FLAG_PACKAGE_PRIVATE; 276 } 277 278 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 279 if (kind == ClassKind.OBJECT) { 280 return NO_FLAG_PACKAGE_PRIVATE; 281 } 282 else if (kind == ClassKind.ENUM_ENTRY) { 283 return NO_FLAG_PACKAGE_PRIVATE; 284 } 285 else if (kind == ClassKind.ENUM_CLASS) { 286 //TODO: should be ACC_PRIVATE 287 // see http://youtrack.jetbrains.com/issue/KT-2680 288 return ACC_PROTECTED; 289 } 290 } 291 if (containingDeclaration instanceof PackageFragmentDescriptor) { 292 return ACC_PUBLIC; 293 } 294 return null; 295 } 296 297 @NotNull 298 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) { 299 JetType jetType = getSuperClass(traitDescriptor); 300 Type type = typeMapper.mapType(jetType); 301 if (type.getInternalName().equals("java/lang/Object")) { 302 return typeMapper.mapType(traitDescriptor.getDefaultType()); 303 } 304 return type; 305 } 306 307 private static Type stringValueOfOrStringBuilderAppendType(Type type) { 308 int sort = type.getSort(); 309 return sort == Type.OBJECT || sort == Type.ARRAY 310 ? AsmTypeConstants.OBJECT_TYPE 311 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 312 } 313 314 public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) { 315 InstructionAdapter iv = new InstructionAdapter(mv); 316 iv.anew(Type.getObjectType(exception)); 317 iv.dup(); 318 iv.aconst(message); 319 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V"); 320 iv.athrow(); 321 } 322 323 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 324 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>(); 325 326 ClassifierDescriptor captureThis = closure.getCaptureThis(); 327 if (captureThis != null) { 328 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis))); 329 } 330 331 JetType captureReceiverType = closure.getCaptureReceiverType(); 332 if (captureReceiverType != null) { 333 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType))); 334 } 335 336 allFields.addAll(closure.getRecordedFields()); 337 genClosureFields(allFields, v); 338 } 339 340 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) { 341 //noinspection PointlessBitwiseExpression 342 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 343 for (Pair<String, Type> field : allFields) { 344 builder.newField(null, access, field.first, field.second.getDescriptor(), null, null); 345 } 346 } 347 348 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) { 349 List<FieldInfo> result = new ArrayList<FieldInfo>(); 350 for (Pair<String, Type> field : allFields) { 351 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); 352 } 353 return result; 354 } 355 356 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 357 assert !info.isStatic(); 358 Type fieldType = info.getFieldType(); 359 iv.load(0, info.getOwnerType());//this 360 iv.load(index, fieldType); //param 361 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 362 index += fieldType.getSize(); 363 return index; 364 } 365 366 public static void genStringBuilderConstructor(InstructionAdapter v) { 367 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 368 v.dup(); 369 v.invokespecial("java/lang/StringBuilder", "<init>", "()V"); 370 } 371 372 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 373 type = stringValueOfOrStringBuilderAppendType(type); 374 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;"); 375 } 376 377 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) { 378 Type type = stringValueOfOrStringBuilderAppendType(receiverType); 379 receiver.put(type, v); 380 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;"); 381 return StackValue.onStack(JAVA_STRING_TYPE); 382 } 383 384 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 385 if (type.getSort() == Type.ARRAY) { 386 Type elementType = correctElementType(type); 387 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 388 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I"); 389 } 390 else { 391 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I"); 392 } 393 } 394 else if (type.getSort() == Type.OBJECT) { 395 iv.invokevirtual("java/lang/Object", "hashCode", "()I"); 396 } 397 else if (type.getSort() == Type.LONG) { 398 genLongHashCode(mv, iv); 399 } 400 else if (type.getSort() == Type.DOUBLE) { 401 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J"); 402 genLongHashCode(mv, iv); 403 } 404 else if (type.getSort() == Type.FLOAT) { 405 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I"); 406 } 407 else if (type.getSort() == Type.BOOLEAN) { 408 Label end = new Label(); 409 iv.dup(); 410 iv.ifeq(end); 411 iv.pop(); 412 iv.iconst(1); 413 iv.mark(end); 414 } 415 else { // byte short char int 416 // do nothing 417 } 418 } 419 420 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 421 iv.dup2(); 422 iv.iconst(32); 423 iv.ushr(Type.LONG_TYPE); 424 iv.xor(Type.LONG_TYPE); 425 mv.visitInsn(L2I); 426 } 427 428 static void genInvertBoolean(InstructionAdapter v) { 429 v.iconst(1); 430 v.xor(Type.INT_TYPE); 431 } 432 433 public static StackValue genEqualsForExpressionsOnStack( 434 InstructionAdapter v, 435 IElementType opToken, 436 Type leftType, 437 Type rightType 438 ) { 439 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) { 440 return StackValue.cmp(opToken, leftType); 441 } 442 else { 443 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 444 return StackValue.cmp(opToken, leftType); 445 } 446 else { 447 v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z"); 448 449 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 450 genInvertBoolean(v); 451 } 452 453 return StackValue.onStack(Type.BOOLEAN_TYPE); 454 } 455 } 456 } 457 458 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 459 if (expectedType == Type.LONG_TYPE) { 460 v.lconst(myDelta); 461 } 462 else if (expectedType == Type.FLOAT_TYPE) { 463 v.fconst(myDelta); 464 } 465 else if (expectedType == Type.DOUBLE_TYPE) { 466 v.dconst(myDelta); 467 } 468 else { 469 v.iconst(myDelta); 470 v.add(Type.INT_TYPE); 471 StackValue.coerce(Type.INT_TYPE, expectedType, v); 472 return; 473 } 474 v.add(expectedType); 475 } 476 477 public static Type genNegate(Type expectedType, InstructionAdapter v) { 478 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) { 479 expectedType = Type.INT_TYPE; 480 } 481 v.neg(expectedType); 482 return expectedType; 483 } 484 485 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 486 if (stackTop.getSize() == 1) { 487 if (afterTop.getSize() == 1) { 488 v.swap(); 489 } else { 490 v.dupX2(); 491 v.pop(); 492 } 493 } else { 494 if (afterTop.getSize() == 1) { 495 v.dup2X1(); 496 } else { 497 v.dup2X2(); 498 } 499 v.pop2(); 500 } 501 } 502 503 public static void genNotNullAssertionsForParameters( 504 @NotNull InstructionAdapter v, 505 @NotNull GenerationState state, 506 @NotNull FunctionDescriptor descriptor, 507 @NotNull FrameMap frameMap 508 ) { 509 if (!state.isGenerateNotNullParamAssertions()) return; 510 511 // Private method is not accessible from other classes, no assertions needed 512 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 513 514 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 515 JetType type = parameter.getReturnType(); 516 if (type == null || isNullableType(type)) continue; 517 518 int index = frameMap.getIndex(parameter); 519 Type asmType = state.getTypeMapper().mapType(type); 520 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 521 v.load(index, asmType); 522 v.visitLdcInsn(parameter.getName().asString()); 523 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V"); 524 } 525 } 526 } 527 528 public static void genNotNullAssertionForField( 529 @NotNull InstructionAdapter v, 530 @NotNull GenerationState state, 531 @NotNull PropertyDescriptor descriptor 532 ) { 533 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 534 } 535 536 public static void genNotNullAssertionForMethod( 537 @NotNull InstructionAdapter v, 538 @NotNull GenerationState state, 539 @NotNull ResolvedCall resolvedCall 540 ) { 541 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 542 if (descriptor instanceof ConstructorDescriptor) return; 543 544 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 545 } 546 547 private static void genNotNullAssertion( 548 @NotNull InstructionAdapter v, 549 @NotNull GenerationState state, 550 @NotNull CallableDescriptor descriptor, 551 @NotNull String assertMethodToCall 552 ) { 553 if (!state.isGenerateNotNullAssertions()) return; 554 555 if (!isDeclaredInJava(descriptor)) return; 556 557 JetType type = descriptor.getReturnType(); 558 if (type == null || isNullableType(type)) return; 559 560 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 561 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 562 v.dup(); 563 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 564 v.visitLdcInsn(descriptor.getName().asString()); 565 v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V"); 566 } 567 } 568 569 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 570 CallableDescriptor descriptor = callableDescriptor; 571 while (true) { 572 if (descriptor instanceof JavaCallableMemberDescriptor) { 573 return true; 574 } 575 CallableDescriptor original = descriptor.getOriginal(); 576 if (descriptor == original) break; 577 descriptor = original; 578 } 579 return false; 580 } 581 582 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 583 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 584 v.aconst(null); 585 } 586 else { 587 pushDefaultPrimitiveValueOnStack(type, v); 588 } 589 } 590 591 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 592 if (type.getSort() == Type.FLOAT) { 593 v.fconst(0); 594 } 595 else if (type.getSort() == Type.DOUBLE) { 596 v.dconst(0); 597 } 598 else if (type.getSort() == Type.LONG) { 599 v.lconst(0); 600 } 601 else { 602 v.iconst(0); 603 } 604 } 605 606 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 607 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS); 608 } 609 610 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 611 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 612 if (isDelegate || isExtensionProperty) { 613 return ACC_PRIVATE; 614 } else { 615 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE; 616 } 617 } 618 619 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 620 if (!propertyDescriptor.isVar() ) { 621 return propertyDescriptor; 622 } else { 623 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 624 } 625 } 626 627 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 628 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 629 return !propertyDescriptor.isVar() && !isExtensionProperty 630 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT) 631 && areBothAccessorDefault(propertyDescriptor) 632 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 633 } 634 635 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 636 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS); 637 } 638 639 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 640 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 641 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 642 } 643 644 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 645 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 646 } 647 648 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) { 649 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind); 650 } 651 652 public static Type comparisonOperandType(Type left, Type right) { 653 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 654 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 655 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 656 return Type.INT_TYPE; 657 } 658 659 @NotNull 660 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 661 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) { 662 return Type.INT_TYPE; 663 } 664 return expectedType; 665 } 666 667 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) { 668 if (type.getSize() == 2) { 669 v.pop2(); 670 } 671 else { 672 v.pop(); 673 } 674 } 675 676 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 677 if (type.getSize() == 2) { 678 v.dup2(); 679 } 680 else { 681 v.dup(); 682 } 683 } 684 685 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 686 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 687 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 688 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), 689 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 690 kind.toString()); 691 av.visitEnd(); 692 } 693 694 @NotNull 695 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 696 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 697 } 698 699 @NotNull 700 public static String shortNameByAsmType(@NotNull Type type) { 701 String internalName = type.getInternalName(); 702 int lastSlash = internalName.lastIndexOf('/'); 703 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 704 } 705 706 @NotNull 707 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 708 return Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName()); 709 } 710 }