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 kotlin.Function1; 024 import kotlin.Unit; 025 import org.jetbrains.annotations.NotNull; 026 import org.jetbrains.annotations.Nullable; 027 import org.jetbrains.jet.codegen.binding.CalculatedClosure; 028 import org.jetbrains.jet.codegen.binding.CodegenBinding; 029 import org.jetbrains.jet.codegen.context.CodegenContext; 030 import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; 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.psi.JetFile; 035 import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; 036 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 037 import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage; 038 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 039 import org.jetbrains.jet.lang.resolve.java.*; 040 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor; 041 import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin; 042 import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils; 043 import org.jetbrains.jet.lang.resolve.name.FqName; 044 import org.jetbrains.jet.lang.types.Approximation; 045 import org.jetbrains.jet.lang.types.JetType; 046 import org.jetbrains.jet.lang.types.TypesPackage; 047 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 048 import org.jetbrains.jet.lexer.JetTokens; 049 import org.jetbrains.org.objectweb.asm.*; 050 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 051 import org.jetbrains.org.objectweb.asm.commons.Method; 052 053 import java.util.ArrayList; 054 import java.util.List; 055 import java.util.Map; 056 import java.util.Set; 057 058 import static org.jetbrains.jet.codegen.JvmCodegenUtil.isInterface; 059 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; 060 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; 061 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType; 062 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; 063 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; 064 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive; 065 import static org.jetbrains.jet.lang.types.TypeUtils.isNullableType; 066 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 067 068 public class AsmUtil { 069 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( 070 KotlinBuiltIns.getInstance().getByte(), 071 KotlinBuiltIns.getInstance().getShort(), 072 KotlinBuiltIns.getInstance().getInt(), 073 KotlinBuiltIns.getInstance().getLong(), 074 KotlinBuiltIns.getInstance().getFloat(), 075 KotlinBuiltIns.getInstance().getDouble(), 076 KotlinBuiltIns.getInstance().getChar() 077 ); 078 079 private static final Set<Type> STRING_BUILDER_OBJECT_APPEND_ARG_TYPES = Sets.newHashSet( 080 getType(String.class), 081 getType(StringBuffer.class), 082 getType(CharSequence.class) 083 ); 084 085 private static final int NO_FLAG_LOCAL = 0; 086 public static final int NO_FLAG_PACKAGE_PRIVATE = 0; 087 088 @NotNull 089 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder() 090 .put(Visibilities.PRIVATE, ACC_PRIVATE) 091 .put(Visibilities.PROTECTED, ACC_PROTECTED) 092 .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED) 093 .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED) 094 .put(Visibilities.PUBLIC, ACC_PUBLIC) 095 .put(Visibilities.INTERNAL, ACC_PUBLIC) 096 .put(Visibilities.LOCAL, NO_FLAG_LOCAL) 097 .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE) 098 .build(); 099 100 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0"; 101 public static final String CAPTURED_THIS_FIELD = "this$0"; 102 103 private static final ImmutableMap<Integer, JvmPrimitiveType> primitiveTypeByAsmSort; 104 private static final ImmutableMap<Type, Type> primitiveTypeByBoxedType; 105 106 static { 107 ImmutableMap.Builder<Integer, JvmPrimitiveType> typeBySortBuilder = ImmutableMap.builder(); 108 ImmutableMap.Builder<Type, Type> typeByWrapperBuilder = ImmutableMap.builder(); 109 for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) { 110 Type asmType = asmTypeForPrimitive(primitiveType); 111 typeBySortBuilder.put(asmType.getSort(), primitiveType); 112 typeByWrapperBuilder.put(asmTypeByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()), asmType); 113 } 114 primitiveTypeByAsmSort = typeBySortBuilder.build(); 115 primitiveTypeByBoxedType = typeByWrapperBuilder.build(); 116 } 117 118 private AsmUtil() { 119 } 120 121 @NotNull 122 public static Type boxType(@NotNull Type type) { 123 JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort()); 124 return jvmPrimitiveType != null ? asmTypeByFqNameWithoutInnerClasses(jvmPrimitiveType.getWrapperFqName()) : type; 125 } 126 127 @NotNull 128 public static Type unboxType(@NotNull Type boxedType) { 129 Type primitiveType = primitiveTypeByBoxedType.get(boxedType); 130 if (primitiveType == null) { 131 throw new UnsupportedOperationException("Unboxing: " + boxedType); 132 } 133 return primitiveType; 134 } 135 136 public static boolean isIntPrimitive(Type type) { 137 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; 138 } 139 140 public static boolean isNumberPrimitive(Type type) { 141 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; 142 } 143 144 public static boolean isPrimitive(Type type) { 145 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY; 146 } 147 148 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) { 149 if (!(descriptor instanceof ClassDescriptor)) { 150 return false; 151 } 152 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor); 153 } 154 155 public static Type correctElementType(Type type) { 156 String internalName = type.getInternalName(); 157 assert internalName.charAt(0) == '['; 158 return Type.getType(internalName.substring(1)); 159 } 160 161 @NotNull 162 public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) { 163 return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes)); 164 } 165 166 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { 167 return (functionDescriptor.getModality() == Modality.ABSTRACT 168 || isInterface(functionDescriptor.getContainingDeclaration())) 169 && !isStaticMethod(kind, functionDescriptor); 170 } 171 172 public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) { 173 return isStaticKind(kind) || 174 JetTypeMapper.isAccessor(functionDescriptor) || 175 AnnotationsPackage.isPlatformStaticInObject(functionDescriptor); 176 } 177 178 public static boolean isStaticKind(OwnerKind kind) { 179 return kind == OwnerKind.PACKAGE || kind == OwnerKind.TRAIT_IMPL; 180 } 181 182 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { 183 int flags = getCommonCallableFlags(functionDescriptor); 184 185 for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) { 186 if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) { 187 flags |= flagAnnotation.getJvmFlag(); 188 } 189 } 190 191 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { 192 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); 193 if (!(containingDeclaration instanceof ClassDescriptor) || 194 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { 195 flags |= ACC_FINAL; 196 } 197 } 198 199 if (isStaticMethod(kind, functionDescriptor)) { 200 flags |= ACC_STATIC; 201 } 202 203 if (isAbstractMethod(functionDescriptor, kind)) { 204 flags |= ACC_ABSTRACT; 205 } 206 207 if (JetTypeMapper.isAccessor(functionDescriptor)) { 208 flags |= ACC_SYNTHETIC; 209 } 210 211 return flags; 212 } 213 214 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) { 215 int flags = getVisibilityAccessFlag(functionDescriptor); 216 flags |= getVarargsFlag(functionDescriptor); 217 flags |= getDeprecatedAccessFlag(functionDescriptor); 218 return flags; 219 } 220 221 //TODO: move mapping logic to front-end java 222 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) { 223 Integer specialCase = specialCaseVisibility(descriptor); 224 if (specialCase != null) { 225 return specialCase; 226 } 227 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility()); 228 if (defaultMapping == null) { 229 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend: " + descriptor); 230 } 231 return defaultMapping; 232 } 233 234 /* 235 Use this method to get visibility flag for class to define it in byte code (v.defineClass method). 236 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) 237 Classes in byte code should be public or package private 238 */ 239 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) { 240 if (DescriptorUtils.isTopLevelDeclaration(descriptor) || 241 descriptor.getVisibility() == Visibilities.PUBLIC || 242 descriptor.getVisibility() == Visibilities.INTERNAL) { 243 return ACC_PUBLIC; 244 } 245 return NO_FLAG_PACKAGE_PRIVATE; 246 } 247 248 public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) { 249 if (isDeclarationInsideInlineFunction(descriptor)) { 250 return ACC_PUBLIC; 251 } 252 return NO_FLAG_PACKAGE_PRIVATE; 253 } 254 255 private static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) { 256 //NB: constructor context couldn't be inline 257 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration(); 258 if (parentDeclaration instanceof SimpleFunctionDescriptor && 259 ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) { 260 return true; 261 } 262 return false; 263 } 264 265 public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) { 266 return getVisibilityAccessFlag(innerClass) | 267 innerAccessFlagsForModalityAndKind(innerClass) | 268 (innerClass.isInner() ? 0 : ACC_STATIC); 269 } 270 271 private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) { 272 switch (innerClass.getKind()) { 273 case TRAIT: 274 return ACC_ABSTRACT | ACC_INTERFACE; 275 case ENUM_CLASS: 276 return ACC_FINAL | ACC_ENUM; 277 case ANNOTATION_CLASS: 278 return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE; 279 default: 280 if (innerClass.getModality() == Modality.FINAL) { 281 return ACC_FINAL; 282 } 283 else if (innerClass.getModality() == Modality.ABSTRACT) { 284 return ACC_ABSTRACT; 285 } 286 } 287 return 0; 288 } 289 290 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { 291 if (descriptor instanceof PropertyAccessorDescriptor) { 292 return KotlinBuiltIns.getInstance().isDeprecated(descriptor) 293 ? ACC_DEPRECATED 294 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()); 295 } 296 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) { 297 return ACC_DEPRECATED; 298 } 299 return 0; 300 } 301 302 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) { 303 if (!functionDescriptor.getValueParameters().isEmpty() 304 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1) 305 .getVarargElementType() != null) { 306 return ACC_VARARGS; 307 } 308 return 0; 309 } 310 311 @Nullable 312 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) { 313 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration(); 314 if (isInterface(containingDeclaration)) { 315 return ACC_PUBLIC; 316 } 317 Visibility memberVisibility = memberDescriptor.getVisibility(); 318 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) { 319 return ACC_PUBLIC; 320 } 321 if (isEnumEntry(memberDescriptor)) { 322 return NO_FLAG_PACKAGE_PRIVATE; 323 } 324 if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) { 325 return NO_FLAG_PACKAGE_PRIVATE; 326 } 327 if (memberVisibility != Visibilities.PRIVATE) { 328 return null; 329 } 330 // the following code is only for PRIVATE visibility of member 331 if (memberDescriptor instanceof ConstructorDescriptor) { 332 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); 333 if (kind == ClassKind.OBJECT || kind == ClassKind.ENUM_ENTRY) { 334 return NO_FLAG_PACKAGE_PRIVATE; 335 } 336 if (kind == ClassKind.ENUM_CLASS) { 337 //TODO: should be ACC_PRIVATE 338 // see http://youtrack.jetbrains.com/issue/KT-2680 339 return ACC_PROTECTED; 340 } 341 } 342 if (containingDeclaration instanceof PackageFragmentDescriptor) { 343 return ACC_PUBLIC; 344 } 345 return null; 346 } 347 348 private static Type stringValueOfType(Type type) { 349 int sort = type.getSort(); 350 return sort == Type.OBJECT || sort == Type.ARRAY 351 ? AsmTypeConstants.OBJECT_TYPE 352 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type; 353 } 354 355 private static Type stringBuilderAppendType(Type type) { 356 switch (type.getSort()) { 357 case Type.OBJECT: 358 return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : AsmTypeConstants.OBJECT_TYPE; 359 case Type.ARRAY: 360 return AsmTypeConstants.OBJECT_TYPE; 361 case Type.BYTE: 362 case Type.SHORT: 363 return Type.INT_TYPE; 364 default: 365 return type; 366 } 367 } 368 369 public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) { 370 v.anew(Type.getObjectType(exception)); 371 v.dup(); 372 if (message != null) { 373 v.aconst(message); 374 v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false); 375 } 376 else { 377 v.invokespecial(exception, "<init>", "()V", false); 378 } 379 v.athrow(); 380 } 381 382 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { 383 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>(); 384 385 ClassifierDescriptor captureThis = closure.getCaptureThis(); 386 if (captureThis != null) { 387 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis))); 388 } 389 390 JetType captureReceiverType = closure.getCaptureReceiverType(); 391 if (captureReceiverType != null) { 392 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType))); 393 } 394 395 allFields.addAll(closure.getRecordedFields()); 396 genClosureFields(allFields, v); 397 } 398 399 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) { 400 //noinspection PointlessBitwiseExpression 401 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL; 402 for (Pair<String, Type> field : allFields) { 403 builder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null); 404 } 405 } 406 407 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) { 408 List<FieldInfo> result = new ArrayList<FieldInfo>(); 409 for (Pair<String, Type> field : allFields) { 410 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); 411 } 412 return result; 413 } 414 415 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { 416 assert !info.isStatic(); 417 Type fieldType = info.getFieldType(); 418 iv.load(0, info.getOwnerType());//this 419 iv.load(index, fieldType); //param 420 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor()); 421 index += fieldType.getSize(); 422 return index; 423 } 424 425 public static void genStringBuilderConstructor(InstructionAdapter v) { 426 v.visitTypeInsn(NEW, "java/lang/StringBuilder"); 427 v.dup(); 428 v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false); 429 } 430 431 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) { 432 type = stringBuilderAppendType(type); 433 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false); 434 } 435 436 public static StackValue genToString(final StackValue receiver, final Type receiverType) { 437 return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() { 438 @Override 439 public Unit invoke(InstructionAdapter v) { 440 Type type = stringValueOfType(receiverType); 441 receiver.put(type, v); 442 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false); 443 return null; 444 } 445 }); 446 } 447 448 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) { 449 if (type.getSort() == Type.ARRAY) { 450 Type elementType = correctElementType(type); 451 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 452 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false); 453 } 454 else { 455 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false); 456 } 457 } 458 else if (type.getSort() == Type.OBJECT) { 459 iv.invokevirtual("java/lang/Object", "hashCode", "()I", false); 460 } 461 else if (type.getSort() == Type.LONG) { 462 genLongHashCode(mv, iv); 463 } 464 else if (type.getSort() == Type.DOUBLE) { 465 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false); 466 genLongHashCode(mv, iv); 467 } 468 else if (type.getSort() == Type.FLOAT) { 469 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false); 470 } 471 else if (type.getSort() == Type.BOOLEAN) { 472 Label end = new Label(); 473 iv.dup(); 474 iv.ifeq(end); 475 iv.pop(); 476 iv.iconst(1); 477 iv.mark(end); 478 } 479 else { // byte short char int 480 // do nothing 481 } 482 } 483 484 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) { 485 iv.dup2(); 486 iv.iconst(32); 487 iv.ushr(Type.LONG_TYPE); 488 iv.xor(Type.LONG_TYPE); 489 mv.visitInsn(L2I); 490 } 491 492 static void genInvertBoolean(InstructionAdapter v) { 493 v.iconst(1); 494 v.xor(Type.INT_TYPE); 495 } 496 497 @NotNull 498 public static StackValue genEqualsForExpressionsOnStack( 499 final @NotNull IElementType opToken, 500 final @NotNull StackValue left, 501 final @NotNull StackValue right 502 ) { 503 final Type leftType = left.type; 504 final Type rightType = right.type; 505 if (isPrimitive(leftType) && leftType == rightType) { 506 return StackValue.cmp(opToken, leftType, left, right); 507 } 508 509 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 510 return StackValue.cmp(opToken, leftType, left, right); 511 } 512 513 return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() { 514 @Override 515 public Unit invoke(InstructionAdapter v) { 516 left.put(leftType, v); 517 right.put(rightType, v); 518 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false); 519 520 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { 521 genInvertBoolean(v); 522 } 523 return Unit.INSTANCE$; 524 } 525 }); 526 } 527 528 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) { 529 if (expectedType == Type.LONG_TYPE) { 530 v.lconst(myDelta); 531 } 532 else if (expectedType == Type.FLOAT_TYPE) { 533 v.fconst(myDelta); 534 } 535 else if (expectedType == Type.DOUBLE_TYPE) { 536 v.dconst(myDelta); 537 } 538 else { 539 v.iconst(myDelta); 540 v.add(Type.INT_TYPE); 541 StackValue.coerce(Type.INT_TYPE, expectedType, v); 542 return; 543 } 544 v.add(expectedType); 545 } 546 547 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) { 548 if (stackTop.getSize() == 1) { 549 if (afterTop.getSize() == 1) { 550 v.swap(); 551 } 552 else { 553 v.dupX2(); 554 v.pop(); 555 } 556 } 557 else { 558 if (afterTop.getSize() == 1) { 559 v.dup2X1(); 560 } 561 else { 562 v.dup2X2(); 563 } 564 v.pop2(); 565 } 566 } 567 568 public static void genNotNullAssertionsForParameters( 569 @NotNull InstructionAdapter v, 570 @NotNull GenerationState state, 571 @NotNull FunctionDescriptor descriptor, 572 @NotNull FrameMap frameMap 573 ) { 574 if (!state.isParamAssertionsEnabled()) return; 575 576 // Private method is not accessible from other classes, no assertions needed 577 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return; 578 579 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { 580 JetType type = parameter.getReturnType(); 581 if (type == null || isNullableType(type)) continue; 582 583 int index = frameMap.getIndex(parameter); 584 Type asmType = state.getTypeMapper().mapType(type); 585 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 586 v.load(index, asmType); 587 v.visitLdcInsn(parameter.getName().asString()); 588 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull", 589 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 590 } 591 } 592 } 593 594 public static void genNotNullAssertionForField( 595 @NotNull InstructionAdapter v, 596 @NotNull GenerationState state, 597 @NotNull PropertyDescriptor descriptor 598 ) { 599 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull"); 600 } 601 602 public static void genNotNullAssertionForMethod( 603 @NotNull InstructionAdapter v, 604 @NotNull GenerationState state, 605 @NotNull ResolvedCall resolvedCall 606 ) { 607 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 608 if (descriptor instanceof ConstructorDescriptor) return; 609 610 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull"); 611 } 612 613 private static void genNotNullAssertion( 614 @NotNull InstructionAdapter v, 615 @NotNull GenerationState state, 616 @NotNull CallableDescriptor descriptor, 617 @NotNull String assertMethodToCall 618 ) { 619 // Assertions are generated elsewhere for platform types 620 if (JavaPackage.getPLATFORM_TYPES()) return; 621 622 if (!state.isCallAssertionsEnabled()) return; 623 624 if (!isDeclaredInJava(descriptor)) return; 625 626 JetType type = descriptor.getReturnType(); 627 if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return; 628 629 Type asmType = state.getTypeMapper().mapReturnType(descriptor); 630 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { 631 v.dup(); 632 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString()); 633 v.visitLdcInsn(descriptor.getName().asString()); 634 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, assertMethodToCall, 635 "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false); 636 } 637 } 638 639 @NotNull 640 public static StackValue genNotNullAssertions( 641 @NotNull GenerationState state, 642 @NotNull final StackValue stackValue, 643 @Nullable final Approximation.Info approximationInfo 644 ) { 645 if (!state.isCallAssertionsEnabled()) return stackValue; 646 if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue; 647 648 return new StackValue(stackValue.type) { 649 650 @Override 651 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { 652 stackValue.put(type, v); 653 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 654 v.dup(); 655 v.visitLdcInsn(approximationInfo.getMessage()); 656 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull", 657 "(Ljava/lang/Object;Ljava/lang/String;)V", false); 658 } 659 } 660 }; 661 } 662 663 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) { 664 CallableDescriptor descriptor = callableDescriptor; 665 while (true) { 666 if (descriptor instanceof JavaCallableMemberDescriptor) { 667 return true; 668 } 669 CallableDescriptor original = descriptor.getOriginal(); 670 if (descriptor == original) break; 671 descriptor = original; 672 } 673 return false; 674 } 675 676 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 677 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 678 v.aconst(null); 679 } 680 else { 681 pushDefaultPrimitiveValueOnStack(type, v); 682 } 683 } 684 685 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { 686 if (type.getSort() == Type.FLOAT) { 687 v.fconst(0); 688 } 689 else if (type.getSort() == Type.DOUBLE) { 690 v.dconst(0); 691 } 692 else if (type.getSort() == Type.LONG) { 693 v.lconst(0); 694 } 695 else { 696 v.iconst(0); 697 } 698 } 699 700 public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) { 701 if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 702 return false; 703 } 704 705 return isObject(propertyDescriptor.getContainingDeclaration()) || isPropertyWithBackingFieldInOuterClass(propertyDescriptor); 706 } 707 708 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 709 return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && 710 isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration()); 711 } 712 713 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { 714 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 715 if (isDelegate || isExtensionProperty) { 716 return ACC_PRIVATE; 717 } 718 else { 719 return areBothAccessorDefault(propertyDescriptor) 720 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) 721 : ACC_PRIVATE; 722 } 723 } 724 725 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { 726 if (!propertyDescriptor.isVar()) { 727 return propertyDescriptor; 728 } 729 else { 730 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; 731 } 732 } 733 734 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { 735 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 736 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration(); 737 return !propertyDescriptor.isVar() 738 && !isExtensionProperty 739 && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration()) 740 && areBothAccessorDefault(propertyDescriptor) 741 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; 742 } 743 744 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { 745 DeclarationDescriptor containingClass = classObject.getContainingDeclaration(); 746 return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass)); 747 } 748 749 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { 750 return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) 751 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); 752 } 753 754 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 755 return accessorDescriptor == null || !accessorDescriptor.hasBody(); 756 } 757 758 public static Type comparisonOperandType(Type left, Type right) { 759 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 760 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; 761 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; 762 return Type.INT_TYPE; 763 } 764 765 @NotNull 766 public static Type numberFunctionOperandType(@NotNull Type expectedType) { 767 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) { 768 return Type.INT_TYPE; 769 } 770 return expectedType; 771 } 772 773 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) { 774 if (type.getSize() == 2) { 775 v.visitInsn(Opcodes.POP2); 776 } 777 else { 778 v.visitInsn(Opcodes.POP); 779 } 780 } 781 782 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { 783 int size = type.getSize(); 784 if (size == 2) { 785 v.dup2(); 786 } 787 else if (size == 1) { 788 v.dup(); 789 } 790 else { 791 throw new UnsupportedOperationException(); 792 } 793 } 794 795 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { 796 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); 797 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 798 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), 799 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), 800 kind.toString()); 801 av.visitEnd(); 802 } 803 804 @NotNull 805 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 806 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor(); 807 } 808 809 @NotNull 810 public static String shortNameByAsmType(@NotNull Type type) { 811 String internalName = type.getInternalName(); 812 int lastSlash = internalName.lastIndexOf('/'); 813 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1); 814 } 815 816 @NotNull 817 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 818 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName)); 819 } 820 821 @NotNull 822 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) { 823 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName(); 824 } 825 826 public static void writeOuterClassAndEnclosingMethod( 827 @NotNull ClassDescriptor descriptor, 828 @NotNull DeclarationDescriptor originalDescriptor, 829 @NotNull JetTypeMapper typeMapper, 830 @NotNull ClassBuilder v 831 ) { 832 String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper); 833 FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class); 834 835 if (function != null) { 836 Method method = typeMapper.mapSignature(function).getAsmMethod(); 837 v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor()); 838 } 839 else { 840 v.visitOuterClass(outerClassName, null, null); 841 } 842 } 843 844 @NotNull 845 private static String getOuterClassName( 846 @NotNull ClassDescriptor classDescriptor, 847 @NotNull DeclarationDescriptor originalDescriptor, 848 @NotNull JetTypeMapper typeMapper 849 ) { 850 DeclarationDescriptor container = classDescriptor.getContainingDeclaration(); 851 while (container != null) { 852 if (container instanceof ClassDescriptor) { 853 return typeMapper.mapClass((ClassDescriptor) container).getInternalName(); 854 } 855 else if (CodegenBinding.isLocalFunOrLambda(container)) { 856 ClassDescriptor descriptor = 857 CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container); 858 return typeMapper.mapClass(descriptor).getInternalName(); 859 } 860 861 container = container.getContainingDeclaration(); 862 } 863 864 JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor); 865 assert containingFile != null : "Containing file should be present for " + classDescriptor; 866 return PackagePartClassUtils.getPackagePartInternalName(containingFile); 867 } 868 869 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { 870 if (isPrimitive(type)) { 871 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); 872 } 873 else { 874 v.aconst(type); 875 } 876 } 877 878 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) { 879 OwnerKind kind = context.getContextKind(); 880 //Trait always should have this descriptor 881 return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1; 882 } 883 }