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