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