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