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