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