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