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.AnnotationVisitor; 026 import org.jetbrains.asm4.Label; 027 import org.jetbrains.asm4.MethodVisitor; 028 import org.jetbrains.asm4.Type; 029 import org.jetbrains.asm4.commons.InstructionAdapter; 030 import org.jetbrains.jet.codegen.binding.CalculatedClosure; 031 import org.jetbrains.jet.codegen.state.GenerationState; 032 import org.jetbrains.jet.codegen.state.JetTypeMapper; 033 import org.jetbrains.jet.lang.descriptors.*; 034 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 036 import org.jetbrains.jet.lang.resolve.java.*; 037 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor; 038 import org.jetbrains.jet.lang.resolve.name.FqName; 039 import org.jetbrains.jet.lang.types.JetType; 040 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 041 import org.jetbrains.jet.lexer.JetTokens; 042 043 import java.util.ArrayList; 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 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; 053 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; 054 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive; 055 056 public class AsmUtil { 057 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( 058 KotlinBuiltIns.getInstance().getByte(), 059 KotlinBuiltIns.getInstance().getShort(), 060 KotlinBuiltIns.getInstance().getInt(), 061 KotlinBuiltIns.getInstance().getLong(), 062 KotlinBuiltIns.getInstance().getFloat(), 063 KotlinBuiltIns.getInstance().getDouble(), 064 KotlinBuiltIns.getInstance().getChar() 065 ); 066 067 private static final int NO_FLAG_LOCAL = 0; 068 public static final int NO_FLAG_PACKAGE_PRIVATE = 0; 069 070 @NotNull 071 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder() 072 .put(Visibilities.PRIVATE, ACC_PRIVATE) 073 .put(Visibilities.PROTECTED, ACC_PROTECTED) 074 .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED) 075 .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED) 076 .put(Visibilities.PUBLIC, ACC_PUBLIC) 077 .put(Visibilities.INTERNAL, ACC_PUBLIC) 078 .put(Visibilities.LOCAL, NO_FLAG_LOCAL) 079 .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE) 080 .build(); 081 082 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0"; 083 public static final String CAPTURED_THIS_FIELD = "this$0"; 084 085 private static final ImmutableMap<Integer, JvmPrimitiveType> primitiveTypeByAsmSort; 086 private static final ImmutableMap<Type, Type> primitiveTypeByBoxedType; 087 088 static { 089 ImmutableMap.Builder<Integer, JvmPrimitiveType> typeBySortBuilder = ImmutableMap.builder(); 090 ImmutableMap.Builder<Type, Type> typeByWrapperBuilder = ImmutableMap.builder(); 091 for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) { 092 Type asmType = asmTypeForPrimitive(primitiveType); 093 typeBySortBuilder.put(asmType.getSort(), primitiveType); 094 typeByWrapperBuilder.put(asmTypeByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()), asmType); 095 } 096 primitiveTypeByAsmSort = typeBySortBuilder.build(); 097 primitiveTypeByBoxedType = typeByWrapperBuilder.build(); 098 } 099 100 private AsmUtil() { 101 } 102 103 @NotNull 104 public static Type boxType(@NotNull Type type) { 105 JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort()); 106 return jvmPrimitiveType != null ? asmTypeByFqNameWithoutInnerClasses(jvmPrimitiveType.getWrapperFqName()) : type; 107 } 108 109 @NotNull 110 public static Type unboxType(@NotNull Type boxedType) { 111 Type primitiveType = primitiveTypeByBoxedType.get(boxedType); 112 if (primitiveType == null) { 113 throw new UnsupportedOperationException("Unboxing: " + boxedType); 114 } 115 return primitiveType; 116 } 117 118 public static boolean isIntPrimitive(Type type) { 119 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; 120 } 121 122 public static boolean isNumberPrimitive(Type type) { 123 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; 124 } 125 126 public static boolean isPrimitive(Type type) { 127 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY; 128 } 129 130 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) { 131 if (!(descriptor instanceof ClassDescriptor)) { 132 return false; 133 } 134 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor); 135 } 136 137 public static Type correctElementType(Type type) { 138 String internalName = type.getInternalName(); 139 assert internalName.charAt(0) == '['; 140 return Type.getType(internalName.substring(1)); 141 } 142 143 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { 144 return (functionDescriptor.getModality() == Modality.ABSTRACT 145 || isInterface(functionDescriptor.getContainingDeclaration())) 146 && !isStaticMethod(kind, functionDescriptor); 147 } 148 149 public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) { 150 return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor); 151 } 152 153 public static boolean isStatic(OwnerKind kind) { 154 return kind == OwnerKind.PACKAGE || kind == OwnerKind.TRAIT_IMPL; 155 } 156 157 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { 158 int flags = getCommonCallableFlags(functionDescriptor); 159 160 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { 161 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); 162 if (!(containingDeclaration instanceof ClassDescriptor) || 163 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { 164 flags |= ACC_FINAL; 165 } 166 } 167 168 if (isStaticMethod(kind, functionDescriptor)) { 169 flags |= ACC_STATIC; 170 } 171 172 if (isAbstractMethod(functionDescriptor, kind)) { 173 flags |= ACC_ABSTRACT; 174 } 175 176 if (JetTypeMapper.isAccessor(functionDescriptor)) { 177 flags |= ACC_SYNTHETIC; 178 } 179 180 return flags; 181 } 182 183 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) { 184 int flags = getVisibilityAccessFlag(functionDescriptor); 185 flags |= getVarargsFlag(functionDescriptor); 186 flags |= getDeprecatedAccessFlag(functionDescriptor); 187 return flags; 188 } 189 190 //TODO: move mapping logic to front-end java 191 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) { 192 Integer specialCase = specialCaseVisibility(descriptor); 193 if (specialCase != null) { 194 return specialCase; 195 } 196 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility()); 197 if (defaultMapping == null) { 198 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend. Descriptor: " + descriptor); 199 } 200 return defaultMapping; 201 } 202 203 /* 204 Use this method to get visibility flag for class to define it in byte code (v.defineClass method). 205 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) 206 Classes in byte code should be public or package private 207 */ 208 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) { 209 if (DescriptorUtils.isTopLevelDeclaration(descriptor) || 210 descriptor.getVisibility() == Visibilities.PUBLIC || 211 descriptor.getVisibility() == Visibilities.INTERNAL) { 212 return ACC_PUBLIC; 213 } 214 return NO_FLAG_PACKAGE_PRIVATE; 215 } 216 217 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { 218 if (descriptor instanceof PropertyAccessorDescriptor) { 219 return KotlinBuiltIns.getInstance().isDeprecated(descriptor) 220 ? ACC_DEPRECATED 221 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 222 } 223 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) { 224 return ACC_DEPRECATED; 225 } 226 return 0; 227 } 228 229 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 230 if (!functionDescriptor.getValueParameters().isEmpty() 231 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 232 .getVarargElementType() != null) { 233 return ACC_VARARGS; 234 } 235 return 0; 236 } 237 238 @Nullable 239 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 240 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 241 if (isInterface(containingDeclaration)) { 242 return ACC_PUBLIC; 243 } 244 Visibility memberVisibility = memberDescriptor.getVisibility(); 245 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 246 return ACC_PUBLIC; 247 } 248 if (isEnumEntry(memberDescriptor)) { 249 return NO_FLAG_PACKAGE_PRIVATE; 250 } 251 if (memberVisibility != Visibilities.PRIVATE) { 252 return null; 253 } 254 // the following code is only for PRIVATE visibility of member 255 if (memberDescriptor instanceof ConstructorDescriptor) { 256 if (isAnonymousObject(containingDeclaration)) { 257 return NO_FLAG_PACKAGE_PRIVATE; 258 } 259 260 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 261 if (kind == ClassKind.OBJECT) { 262 return NO_FLAG_PACKAGE_PRIVATE; 263 } 264 else if (kind == ClassKind.ENUM_ENTRY) { 265 return NO_FLAG_PACKAGE_PRIVATE; 266 } 267 else if (kind == ClassKind.ENUM_CLASS) { 268 //TODO: should be ACC_PRIVATE 269 // see http://youtrack.jetbrains.com/issue/KT-2680 270 return ACC_PROTECTED; 271 } 272 } 273 if (containingDeclaration instanceof PackageFragmentDescriptor) { 274 return ACC_PUBLIC; 275 } 276 return null; 277 } 278 279 @NotNull 280 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) { 281 JetType jetType = getSuperClass(traitDescriptor); 282 Type type = typeMapper.mapType(jetType); 283 if (type.getInternalName().equals("java/lang/Object")) { 284 return typeMapper.mapType(traitDescriptor.getDefaultType()); 285 } 286 return type; 287 } 288 289 private static Type stringValueOfOrStringBuilderAppendType(Type type) { 290 int sort = type.getSort(); 291 return sort == Type.OBJECT || sort == Type.ARRAY 292 ? AsmTypeConstants.OBJECT_TYPE 293 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 294 } 295 296 public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) { 297 InstructionAdapter iv = new InstructionAdapter(mv); 298 iv.anew(Type.getObjectType(exception)); 299 iv.dup(); 300 iv.aconst(message); 301 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V"); 302 iv.athrow(); 303 } 304 305 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 306 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>(); 307 308 ClassifierDescriptor captureThis = closure.getCaptureThis(); 309 if (captureThis != null) { 310 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis))); 311 } 312 313 JetType captureReceiverType = closure.getCaptureReceiverType(); 314 if (captureReceiverType != null) { 315 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType))); 316 } 317 318 allFields.addAll(closure.getRecordedFields()); 319 genClosureFields(allFields, v); 320 } 321 322 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) { 323 //noinspection PointlessBitwiseExpression 324 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 325 for (Pair<String, Type> field : allFields) { 326 builder.newField(null, access, field.first, field.second.getDescriptor(), null, null); 327 } 328 } 329 330 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) { 331 List<FieldInfo> result = new ArrayList<FieldInfo>(); 332 for (Pair<String, Type> field : allFields) { 333 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); 334 } 335 return result; 336 } 337 338 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 339 assert !info.isStatic(); 340 Type fieldType = info.getFieldType(); 341 iv.load(0, info.getOwnerType());//this 342 iv.load(index, fieldType); //param 343 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 344 index += fieldType.getSize(); 345 return index; 346 } 347 348 public static void genStringBuilderConstructor(InstructionAdapter v) { 349 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 350 v.dup(); 351 v.invokespecial("java/lang/StringBuilder", "<init>", "()V"); 352 } 353 354 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 355 type = stringValueOfOrStringBuilderAppendType(type); 356 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;"); 357 } 358 359 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) { 360 Type type = stringValueOfOrStringBuilderAppendType(receiverType); 361 receiver.put(type, v); 362 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;"); 363 return StackValue.onStack(JAVA_STRING_TYPE); 364 } 365 366 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 367 if (type.getSort() == Type.ARRAY) { 368 Type elementType = correctElementType(type); 369 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 370 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I"); 371 } 372 else { 373 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I"); 374 } 375 } 376 else if (type.getSort() == Type.OBJECT) { 377 iv.invokevirtual("java/lang/Object", "hashCode", "()I"); 378 } 379 else if (type.getSort() == Type.LONG) { 380 genLongHashCode(mv, iv); 381 } 382 else if (type.getSort() == Type.DOUBLE) { 383 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J"); 384 genLongHashCode(mv, iv); 385 } 386 else if (type.getSort() == Type.FLOAT) { 387 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I"); 388 } 389 else if (type.getSort() == Type.BOOLEAN) { 390 Label end = new Label(); 391 iv.dup(); 392 iv.ifeq(end); 393 iv.pop(); 394 iv.iconst(1); 395 iv.mark(end); 396 } 397 else { // byte short char int 398 // do nothing 399 } 400 } 401 402 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 403 iv.dup2(); 404 iv.iconst(32); 405 iv.ushr(Type.LONG_TYPE); 406 iv.xor(Type.LONG_TYPE); 407 mv.visitInsn(L2I); 408 } 409 410 static void genInvertBoolean(InstructionAdapter v) { 411 v.iconst(1); 412 v.xor(Type.INT_TYPE); 413 } 414 415 public static StackValue genEqualsForExpressionsOnStack( 416 InstructionAdapter v, 417 IElementType opToken, 418 Type leftType, 419 Type rightType 420 ) { 421 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) { 422 return StackValue.cmp(opToken, leftType); 423 } 424 else { 425 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 426 return StackValue.cmp(opToken, leftType); 427 } 428 else { 429 v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z"); 430 431 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 432 genInvertBoolean(v); 433 } 434 435 return StackValue.onStack(Type.BOOLEAN_TYPE); 436 } 437 } 438 } 439 440 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 441 if (expectedType == Type.LONG_TYPE) { 442 v.lconst(myDelta); 443 } 444 else if (expectedType == Type.FLOAT_TYPE) { 445 v.fconst(myDelta); 446 } 447 else if (expectedType == Type.DOUBLE_TYPE) { 448 v.dconst(myDelta); 449 } 450 else { 451 v.iconst(myDelta); 452 v.add(Type.INT_TYPE); 453 StackValue.coerce(Type.INT_TYPE, expectedType, v); 454 return; 455 } 456 v.add(expectedType); 457 } 458 459 public static Type genNegate(Type expectedType, InstructionAdapter v) { 460 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) { 461 expectedType = Type.INT_TYPE; 462 } 463 v.neg(expectedType); 464 return expectedType; 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().mapType(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("kotlin/jvm/internal/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(descriptor); 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("kotlin/jvm/internal/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 @NotNull 642 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 643 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) { 644 return Type.INT_TYPE; 645 } 646 return expectedType; 647 } 648 649 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) { 650 if (type.getSize() == 2) { 651 v.pop2(); 652 } 653 else { 654 v.pop(); 655 } 656 } 657 658 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 659 if (type.getSize() == 2) { 660 v.dup2(); 661 } 662 else { 663 v.dup(); 664 } 665 } 666 667 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 668 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 669 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 670 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), 671 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 672 kind.toString()); 673 av.visitEnd(); 674 } 675 676 @NotNull 677 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 678 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 679 } 680 681 @NotNull 682 public static String shortNameByAsmType(@NotNull Type type) { 683 String internalName = type.getInternalName(); 684 int lastSlash = internalName.lastIndexOf('/'); 685 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 686 } 687 688 @NotNull 689 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 690 return Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName()); 691 } 692 }