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 017package org.jetbrains.jet.codegen; 018 019import com.google.common.collect.ImmutableMap; 020import com.google.common.collect.Sets; 021import com.intellij.openapi.util.Pair; 022import com.intellij.psi.tree.IElementType; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.annotations.Nullable; 025import org.jetbrains.asm4.Label; 026import org.jetbrains.asm4.MethodVisitor; 027import org.jetbrains.asm4.Type; 028import org.jetbrains.asm4.commons.InstructionAdapter; 029import org.jetbrains.jet.codegen.binding.CalculatedClosure; 030import org.jetbrains.jet.codegen.state.GenerationState; 031import org.jetbrains.jet.codegen.state.JetTypeMapper; 032import org.jetbrains.jet.lang.descriptors.*; 033import org.jetbrains.jet.lang.resolve.BindingContext; 034import org.jetbrains.jet.lang.resolve.DescriptorUtils; 035import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 036import org.jetbrains.jet.lang.resolve.java.*; 037import org.jetbrains.jet.lang.types.JetType; 038import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 039import org.jetbrains.jet.lexer.JetTokens; 040 041import java.util.List; 042import java.util.Map; 043import java.util.Set; 044 045import static org.jetbrains.asm4.Opcodes.*; 046import static org.jetbrains.jet.codegen.CodegenUtil.*; 047import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; 048import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; 049 050public class AsmUtil { 051 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( 052 KotlinBuiltIns.getInstance().getByte(), 053 KotlinBuiltIns.getInstance().getShort(), 054 KotlinBuiltIns.getInstance().getInt(), 055 KotlinBuiltIns.getInstance().getLong(), 056 KotlinBuiltIns.getInstance().getFloat(), 057 KotlinBuiltIns.getInstance().getDouble(), 058 KotlinBuiltIns.getInstance().getChar() 059 ); 060 061 private static final int NO_FLAG_LOCAL = 0; 062 public static final int NO_FLAG_PACKAGE_PRIVATE = 0; 063 064 @NotNull 065 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder() 066 .put(Visibilities.PRIVATE, ACC_PRIVATE) 067 .put(Visibilities.PROTECTED, ACC_PROTECTED) 068 .put(JavaDescriptorResolver.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED) 069 .put(JavaDescriptorResolver.PROTECTED_AND_PACKAGE, ACC_PROTECTED) 070 .put(Visibilities.PUBLIC, ACC_PUBLIC) 071 .put(Visibilities.INTERNAL, ACC_PUBLIC) 072 .put(Visibilities.LOCAL, NO_FLAG_LOCAL) 073 .put(JavaDescriptorResolver.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE) 074 .build(); 075 076 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0"; 077 public static final String CAPTURED_THIS_FIELD = "this$0"; 078 079 private static final String STUB_EXCEPTION = "java/lang/RuntimeException"; 080 private static final String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath"; 081 082 private AsmUtil() { 083 } 084 085 public static Type boxType(Type asmType) { 086 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByAsmType(asmType); 087 if (jvmPrimitiveType != null) { 088 return jvmPrimitiveType.getWrapper().getAsmType(); 089 } 090 else { 091 return asmType; 092 } 093 } 094 095 public static boolean isIntPrimitive(Type type) { 096 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; 097 } 098 099 public static boolean isNumberPrimitive(Type type) { 100 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; 101 } 102 103 public static boolean isPrimitive(Type type) { 104 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY; 105 } 106 107 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) { 108 if (!(descriptor instanceof ClassDescriptor)) { 109 return false; 110 } 111 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor); 112 } 113 114 public static Type correctElementType(Type type) { 115 String internalName = type.getInternalName(); 116 assert internalName.charAt(0) == '['; 117 return Type.getType(internalName.substring(1)); 118 } 119 120 public static Type unboxType(Type type) { 121 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByWrapperAsmType(type); 122 if (jvmPrimitiveType != null) { 123 return jvmPrimitiveType.getAsmType(); 124 } 125 else { 126 throw new UnsupportedOperationException("Unboxing: " + type); 127 } 128 } 129 130 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { 131 return (functionDescriptor.getModality() == Modality.ABSTRACT 132 || isInterface(functionDescriptor.getContainingDeclaration())) 133 && !isStaticMethod(kind, functionDescriptor); 134 } 135 136 public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) { 137 return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor); 138 } 139 140 public static boolean isStatic(OwnerKind kind) { 141 return kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.TRAIT_IMPL; 142 } 143 144 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { 145 int flags = getCommonCallableFlags(functionDescriptor); 146 147 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { 148 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); 149 if (!(containingDeclaration instanceof ClassDescriptor) || 150 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { 151 flags |= ACC_FINAL; 152 } 153 } 154 155 if (isStaticMethod(kind, functionDescriptor)) { 156 flags |= ACC_STATIC; 157 } 158 159 if (isAbstractMethod(functionDescriptor, kind)) { 160 flags |= ACC_ABSTRACT; 161 } 162 163 if (JetTypeMapper.isAccessor(functionDescriptor)) { 164 flags |= ACC_SYNTHETIC; 165 } 166 167 return flags; 168 } 169 170 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) { 171 int flags = getVisibilityAccessFlag(functionDescriptor); 172 flags |= getVarargsFlag(functionDescriptor); 173 flags |= getDeprecatedAccessFlag(functionDescriptor); 174 return flags; 175 } 176 177 //TODO: move mapping logic to front-end java 178 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) { 179 Integer specialCase = specialCaseVisibility(descriptor); 180 if (specialCase != null) { 181 return specialCase; 182 } 183 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility()); 184 if (defaultMapping == null) { 185 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend."); 186 } 187 return defaultMapping; 188 } 189 190 /* 191 Use this method to get visibility flag for class to define it in byte code (v.defineClass method). 192 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) 193 Classes in byte code should be public or package private 194 */ 195 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) { 196 if (DescriptorUtils.isTopLevelDeclaration(descriptor) || 197 descriptor.getVisibility() == Visibilities.PUBLIC || 198 descriptor.getVisibility() == Visibilities.INTERNAL) { 199 return ACC_PUBLIC; 200 } 201 return NO_FLAG_PACKAGE_PRIVATE; 202 } 203 204 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { 205 if (descriptor instanceof PropertyAccessorDescriptor) { 206 return KotlinBuiltIns.getInstance().isDeprecated(descriptor) 207 ? ACC_DEPRECATED 208 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 209 } 210 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) { 211 return ACC_DEPRECATED; 212 } 213 return 0; 214 } 215 216 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 217 if (!functionDescriptor.getValueParameters().isEmpty() 218 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 219 .getVarargElementType() != null) { 220 return ACC_VARARGS; 221 } 222 return 0; 223 } 224 225 @Nullable 226 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 227 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 228 if (isInterface(containingDeclaration)) { 229 return ACC_PUBLIC; 230 } 231 Visibility memberVisibility = memberDescriptor.getVisibility(); 232 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 233 return ACC_PUBLIC; 234 } 235 if (memberVisibility != Visibilities.PRIVATE) { 236 return null; 237 } 238 // the following code is only for PRIVATE visibility of member 239 if (isEnumEntry(memberDescriptor)) { 240 return NO_FLAG_PACKAGE_PRIVATE; 241 } 242 if (memberDescriptor instanceof ConstructorDescriptor) { 243 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 244 if (kind == ClassKind.OBJECT) { 245 return NO_FLAG_PACKAGE_PRIVATE; 246 } 247 else if (kind == ClassKind.ENUM_ENTRY) { 248 return NO_FLAG_PACKAGE_PRIVATE; 249 } 250 else if (kind == ClassKind.ENUM_CLASS) { 251 //TODO: should be ACC_PRIVATE 252 // see http://youtrack.jetbrains.com/issue/KT-2680 253 return ACC_PROTECTED; 254 } 255 } 256 if (containingDeclaration instanceof NamespaceDescriptor) { 257 return ACC_PUBLIC; 258 } 259 return null; 260 } 261 262 @NotNull 263 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) { 264 JetType jetType = getSuperClass(traitDescriptor); 265 Type type = typeMapper.mapType(jetType); 266 if (type.getInternalName().equals("java/lang/Object")) { 267 return typeMapper.mapType(traitDescriptor.getDefaultType()); 268 } 269 return type; 270 } 271 272 private static Type stringValueOfOrStringBuilderAppendType(Type type) { 273 int sort = type.getSort(); 274 return sort == Type.OBJECT || sort == Type.ARRAY 275 ? AsmTypeConstants.OBJECT_TYPE 276 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 277 } 278 279 public static void genThrow(MethodVisitor mv, String exception, String message) { 280 InstructionAdapter iv = new InstructionAdapter(mv); 281 iv.anew(Type.getObjectType(exception)); 282 iv.dup(); 283 iv.aconst(message); 284 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V"); 285 iv.athrow(); 286 } 287 288 public static void genMethodThrow(MethodVisitor mv, String exception, String message) { 289 mv.visitCode(); 290 genThrow(mv, exception, message); 291 mv.visitMaxs(-1, -1); 292 mv.visitEnd(); 293 } 294 295 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 296 ClassifierDescriptor captureThis = closure.getCaptureThis(); 297 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 298 if (captureThis != null) { 299 v.newField(null, access, CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis).getDescriptor(), null, 300 null); 301 } 302 303 ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); 304 if (captureReceiver != null) { 305 v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiver).getDescriptor(), 306 null, null); 307 } 308 309 List<Pair<String, Type>> fields = closure.getRecordedFields(); 310 for (Pair<String, Type> field : fields) { 311 v.newField(null, access, field.first, field.second.getDescriptor(), null, null); 312 } 313 } 314 315 public static void genInitSingletonField(Type classAsmType, InstructionAdapter iv) { 316 genInitSingletonField(classAsmType, JvmAbi.INSTANCE_FIELD, classAsmType, iv); 317 } 318 319 public static void genInitSingletonField(FieldInfo info, InstructionAdapter iv) { 320 assert info.isStatic(); 321 genInitSingletonField(info.getOwnerType(), info.getFieldName(), info.getFieldType(), iv); 322 } 323 324 public static void genInitSingletonField(Type fieldOwnerType, String fieldName, Type fieldAsmType, InstructionAdapter iv) { 325 iv.anew(fieldAsmType); 326 iv.dup(); 327 iv.invokespecial(fieldAsmType.getInternalName(), "<init>", "()V"); 328 iv.putstatic(fieldOwnerType.getInternalName(), fieldName, fieldAsmType.getDescriptor()); 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 genStubCode(MethodVisitor mv) { 461 genMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE); 462 } 463 464 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 465 if (stackTop.getSize() == 1) { 466 if (afterTop.getSize() == 1) { 467 v.swap(); 468 } else { 469 v.dupX2(); 470 v.pop(); 471 } 472 } else { 473 if (afterTop.getSize() == 1) { 474 v.dup2X1(); 475 } else { 476 v.dup2X2(); 477 } 478 v.pop2(); 479 } 480 } 481 482 public static void genNotNullAssertionsForParameters( 483 @NotNull InstructionAdapter v, 484 @NotNull GenerationState state, 485 @NotNull FunctionDescriptor descriptor, 486 @NotNull FrameMap frameMap 487 ) { 488 if (!state.isGenerateNotNullParamAssertions()) return; 489 490 // Private method is not accessible from other classes, no assertions needed 491 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 492 493 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 494 JetType type = parameter.getReturnType(); 495 if (type == null || isNullableType(type)) continue; 496 497 int index = frameMap.getIndex(parameter); 498 Type asmType = state.getTypeMapper().mapReturnType(type); 499 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 500 v.load(index, asmType); 501 v.visitLdcInsn(parameter.getName().asString()); 502 v.invokestatic("jet/runtime/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V"); 503 } 504 } 505 } 506 507 public static void genNotNullAssertionForField( 508 @NotNull InstructionAdapter v, 509 @NotNull GenerationState state, 510 @NotNull PropertyDescriptor descriptor 511 ) { 512 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 513 } 514 515 public static void genNotNullAssertionForMethod( 516 @NotNull InstructionAdapter v, 517 @NotNull GenerationState state, 518 @NotNull ResolvedCall resolvedCall 519 ) { 520 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 521 if (descriptor instanceof ConstructorDescriptor) return; 522 523 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 524 } 525 526 private static void genNotNullAssertion( 527 @NotNull InstructionAdapter v, 528 @NotNull GenerationState state, 529 @NotNull CallableDescriptor descriptor, 530 @NotNull String assertMethodToCall 531 ) { 532 if (!state.isGenerateNotNullAssertions()) return; 533 534 if (!isDeclaredInJava(descriptor, state.getBindingContext())) return; 535 536 JetType type = descriptor.getReturnType(); 537 if (type == null || isNullableType(type)) return; 538 539 Type asmType = state.getTypeMapper().mapReturnType(type); 540 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 541 v.dup(); 542 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 543 v.visitLdcInsn(descriptor.getName().asString()); 544 v.invokestatic("jet/runtime/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V"); 545 } 546 } 547 548 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor, @NotNull BindingContext context) { 549 CallableDescriptor descriptor = callableDescriptor; 550 while (true) { 551 if (Boolean.TRUE.equals(context.get(JavaBindingContext.IS_DECLARED_IN_JAVA, descriptor))) { 552 return true; 553 } 554 CallableDescriptor original = descriptor.getOriginal(); 555 if (descriptor == original) break; 556 descriptor = original; 557 } 558 return false; 559 } 560 561 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 562 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 563 v.aconst(null); 564 } 565 else { 566 pushDefaultPrimitiveValueOnStack(type, v); 567 } 568 } 569 570 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 571 if (type.getSort() == Type.FLOAT) { 572 v.fconst(0); 573 } 574 else if (type.getSort() == Type.DOUBLE) { 575 v.dconst(0); 576 } 577 else if (type.getSort() == Type.LONG) { 578 v.lconst(0); 579 } 580 else { 581 v.iconst(0); 582 } 583 } 584 585 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 586 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS); 587 } 588 589 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 590 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 591 if (isDelegate || isExtensionProperty) { 592 return ACC_PRIVATE; 593 } else { 594 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE; 595 } 596 } 597 598 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 599 if (!propertyDescriptor.isVar() ) { 600 return propertyDescriptor; 601 } else { 602 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 603 } 604 } 605 606 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 607 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 608 return !propertyDescriptor.isVar() && !isExtensionProperty 609 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT) 610 && areBothAccessorDefault(propertyDescriptor) 611 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 612 } 613 614 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 615 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS); 616 } 617 618 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 619 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 620 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 621 } 622 623 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 624 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 625 } 626 627 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) { 628 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind); 629 } 630 631 public static Type comparisonOperandType(Type left, Type right) { 632 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 633 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 634 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 635 return Type.INT_TYPE; 636 } 637 638 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) { 639 if (type.getSize() == 2) { 640 v.pop2(); 641 } 642 else { 643 v.pop(); 644 } 645 } 646 647 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 648 if (type.getSize() == 2) { 649 v.dup2(); 650 } 651 else { 652 v.dup(); 653 } 654 } 655 656}