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.PACKAGE || 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. Descriptor: " + descriptor); 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 (isEnumEntry(memberDescriptor)) { 248 return NO_FLAG_PACKAGE_PRIVATE; 249 } 250 if (memberVisibility != Visibilities.PRIVATE) { 251 return null; 252 } 253 // the following code is only for PRIVATE visibility of member 254 if (memberDescriptor instanceof ConstructorDescriptor) { 255 if (isAnonymousObject(containingDeclaration)) { 256 return NO_FLAG_PACKAGE_PRIVATE; 257 } 258 259 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 260 if (kind == ClassKind.OBJECT) { 261 return NO_FLAG_PACKAGE_PRIVATE; 262 } 263 else if (kind == ClassKind.ENUM_ENTRY) { 264 return NO_FLAG_PACKAGE_PRIVATE; 265 } 266 else if (kind == ClassKind.ENUM_CLASS) { 267 //TODO: should be ACC_PRIVATE 268 // see http://youtrack.jetbrains.com/issue/KT-2680 269 return ACC_PROTECTED; 270 } 271 } 272 if (containingDeclaration instanceof PackageFragmentDescriptor) { 273 return ACC_PUBLIC; 274 } 275 return null; 276 } 277 278 @NotNull 279 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) { 280 JetType jetType = getSuperClass(traitDescriptor); 281 Type type = typeMapper.mapType(jetType); 282 if (type.getInternalName().equals("java/lang/Object")) { 283 return typeMapper.mapType(traitDescriptor.getDefaultType()); 284 } 285 return type; 286 } 287 288 private static Type stringValueOfOrStringBuilderAppendType(Type type) { 289 int sort = type.getSort(); 290 return sort == Type.OBJECT || sort == Type.ARRAY 291 ? AsmTypeConstants.OBJECT_TYPE 292 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 293 } 294 295 public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) { 296 InstructionAdapter iv = new InstructionAdapter(mv); 297 iv.anew(Type.getObjectType(exception)); 298 iv.dup(); 299 iv.aconst(message); 300 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V"); 301 iv.athrow(); 302 } 303 304 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 305 ClassifierDescriptor captureThis = closure.getCaptureThis(); 306 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 307 if (captureThis != null) { 308 v.newField(null, access, CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis).getDescriptor(), null, 309 null); 310 } 311 312 JetType captureReceiverType = closure.getCaptureReceiverType(); 313 if (captureReceiverType != null) { 314 v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType).getDescriptor(), 315 null, null); 316 } 317 318 List<Pair<String, Type>> fields = closure.getRecordedFields(); 319 for (Pair<String, Type> field : fields) { 320 v.newField(null, access, field.first, field.second.getDescriptor(), null, null); 321 } 322 } 323 324 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 325 assert !info.isStatic(); 326 Type fieldType = info.getFieldType(); 327 iv.load(0, info.getOwnerType());//this 328 iv.load(index, fieldType); //param 329 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 330 index += fieldType.getSize(); 331 return index; 332 } 333 334 public static void genStringBuilderConstructor(InstructionAdapter v) { 335 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 336 v.dup(); 337 v.invokespecial("java/lang/StringBuilder", "<init>", "()V"); 338 } 339 340 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 341 type = stringValueOfOrStringBuilderAppendType(type); 342 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;"); 343 } 344 345 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) { 346 Type type = stringValueOfOrStringBuilderAppendType(receiverType); 347 receiver.put(type, v); 348 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;"); 349 return StackValue.onStack(JAVA_STRING_TYPE); 350 } 351 352 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 353 if (type.getSort() == Type.ARRAY) { 354 Type elementType = correctElementType(type); 355 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 356 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I"); 357 } 358 else { 359 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I"); 360 } 361 } 362 else if (type.getSort() == Type.OBJECT) { 363 iv.invokevirtual("java/lang/Object", "hashCode", "()I"); 364 } 365 else if (type.getSort() == Type.LONG) { 366 genLongHashCode(mv, iv); 367 } 368 else if (type.getSort() == Type.DOUBLE) { 369 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J"); 370 genLongHashCode(mv, iv); 371 } 372 else if (type.getSort() == Type.FLOAT) { 373 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I"); 374 } 375 else if (type.getSort() == Type.BOOLEAN) { 376 Label end = new Label(); 377 iv.dup(); 378 iv.ifeq(end); 379 iv.pop(); 380 iv.iconst(1); 381 iv.mark(end); 382 } 383 else { // byte short char int 384 // do nothing 385 } 386 } 387 388 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 389 iv.dup2(); 390 iv.iconst(32); 391 iv.ushr(Type.LONG_TYPE); 392 iv.xor(Type.LONG_TYPE); 393 mv.visitInsn(L2I); 394 } 395 396 static void genInvertBoolean(InstructionAdapter v) { 397 v.iconst(1); 398 v.xor(Type.INT_TYPE); 399 } 400 401 public static StackValue genEqualsForExpressionsOnStack( 402 InstructionAdapter v, 403 IElementType opToken, 404 Type leftType, 405 Type rightType 406 ) { 407 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) { 408 return StackValue.cmp(opToken, leftType); 409 } 410 else { 411 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 412 return StackValue.cmp(opToken, leftType); 413 } 414 else { 415 v.invokestatic("jet/runtime/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z"); 416 417 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 418 genInvertBoolean(v); 419 } 420 421 return StackValue.onStack(Type.BOOLEAN_TYPE); 422 } 423 } 424 } 425 426 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 427 if (expectedType == Type.LONG_TYPE) { 428 v.lconst(myDelta); 429 } 430 else if (expectedType == Type.FLOAT_TYPE) { 431 v.fconst(myDelta); 432 } 433 else if (expectedType == Type.DOUBLE_TYPE) { 434 v.dconst(myDelta); 435 } 436 else { 437 v.iconst(myDelta); 438 v.add(Type.INT_TYPE); 439 StackValue.coerce(Type.INT_TYPE, expectedType, v); 440 return; 441 } 442 v.add(expectedType); 443 } 444 445 public static Type genNegate(Type expectedType, InstructionAdapter v) { 446 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) { 447 expectedType = Type.INT_TYPE; 448 } 449 v.neg(expectedType); 450 return expectedType; 451 } 452 453 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 454 if (stackTop.getSize() == 1) { 455 if (afterTop.getSize() == 1) { 456 v.swap(); 457 } else { 458 v.dupX2(); 459 v.pop(); 460 } 461 } else { 462 if (afterTop.getSize() == 1) { 463 v.dup2X1(); 464 } else { 465 v.dup2X2(); 466 } 467 v.pop2(); 468 } 469 } 470 471 public static void genNotNullAssertionsForParameters( 472 @NotNull InstructionAdapter v, 473 @NotNull GenerationState state, 474 @NotNull FunctionDescriptor descriptor, 475 @NotNull FrameMap frameMap 476 ) { 477 if (!state.isGenerateNotNullParamAssertions()) return; 478 479 // Private method is not accessible from other classes, no assertions needed 480 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 481 482 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 483 JetType type = parameter.getReturnType(); 484 if (type == null || isNullableType(type)) continue; 485 486 int index = frameMap.getIndex(parameter); 487 Type asmType = state.getTypeMapper().mapType(type); 488 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 489 v.load(index, asmType); 490 v.visitLdcInsn(parameter.getName().asString()); 491 v.invokestatic("jet/runtime/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V"); 492 } 493 } 494 } 495 496 public static void genNotNullAssertionForField( 497 @NotNull InstructionAdapter v, 498 @NotNull GenerationState state, 499 @NotNull PropertyDescriptor descriptor 500 ) { 501 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 502 } 503 504 public static void genNotNullAssertionForMethod( 505 @NotNull InstructionAdapter v, 506 @NotNull GenerationState state, 507 @NotNull ResolvedCall resolvedCall 508 ) { 509 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 510 if (descriptor instanceof ConstructorDescriptor) return; 511 512 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 513 } 514 515 private static void genNotNullAssertion( 516 @NotNull InstructionAdapter v, 517 @NotNull GenerationState state, 518 @NotNull CallableDescriptor descriptor, 519 @NotNull String assertMethodToCall 520 ) { 521 if (!state.isGenerateNotNullAssertions()) return; 522 523 if (!isDeclaredInJava(descriptor)) return; 524 525 JetType type = descriptor.getReturnType(); 526 if (type == null || isNullableType(type)) return; 527 528 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 529 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 530 v.dup(); 531 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 532 v.visitLdcInsn(descriptor.getName().asString()); 533 v.invokestatic("jet/runtime/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V"); 534 } 535 } 536 537 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 538 CallableDescriptor descriptor = callableDescriptor; 539 while (true) { 540 if (descriptor instanceof JavaCallableMemberDescriptor) { 541 return true; 542 } 543 CallableDescriptor original = descriptor.getOriginal(); 544 if (descriptor == original) break; 545 descriptor = original; 546 } 547 return false; 548 } 549 550 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 551 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 552 v.aconst(null); 553 } 554 else { 555 pushDefaultPrimitiveValueOnStack(type, v); 556 } 557 } 558 559 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 560 if (type.getSort() == Type.FLOAT) { 561 v.fconst(0); 562 } 563 else if (type.getSort() == Type.DOUBLE) { 564 v.dconst(0); 565 } 566 else if (type.getSort() == Type.LONG) { 567 v.lconst(0); 568 } 569 else { 570 v.iconst(0); 571 } 572 } 573 574 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 575 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS); 576 } 577 578 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 579 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 580 if (isDelegate || isExtensionProperty) { 581 return ACC_PRIVATE; 582 } else { 583 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE; 584 } 585 } 586 587 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 588 if (!propertyDescriptor.isVar() ) { 589 return propertyDescriptor; 590 } else { 591 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 592 } 593 } 594 595 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 596 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 597 return !propertyDescriptor.isVar() && !isExtensionProperty 598 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT) 599 && areBothAccessorDefault(propertyDescriptor) 600 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 601 } 602 603 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 604 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS); 605 } 606 607 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 608 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 609 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 610 } 611 612 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 613 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 614 } 615 616 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) { 617 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind); 618 } 619 620 public static Type comparisonOperandType(Type left, Type right) { 621 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 622 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 623 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 624 return Type.INT_TYPE; 625 } 626 627 @NotNull 628 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 629 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) { 630 return Type.INT_TYPE; 631 } 632 return expectedType; 633 } 634 635 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) { 636 if (type.getSize() == 2) { 637 v.pop2(); 638 } 639 else { 640 v.pop(); 641 } 642 } 643 644 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 645 if (type.getSize() == 2) { 646 v.dup2(); 647 } 648 else { 649 v.dup(); 650 } 651 } 652 653 @NotNull 654 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 655 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 656 } 657 658 @NotNull 659 public static String shortNameByAsmType(@NotNull Type type) { 660 String internalName = type.getInternalName(); 661 int lastSlash = internalName.lastIndexOf('/'); 662 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 663 } 664 665 @NotNull 666 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 667 return Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName()); 668 } 669 }