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.state.GenerationState;
027 import org.jetbrains.jet.codegen.state.JetTypeMapper;
028 import org.jetbrains.jet.lang.descriptors.*;
029 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
030 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
031 import org.jetbrains.jet.lang.resolve.java.*;
032 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor;
033 import org.jetbrains.jet.lang.resolve.name.FqName;
034 import org.jetbrains.jet.lang.types.JetType;
035 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036 import org.jetbrains.jet.lexer.JetTokens;
037 import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
038 import org.jetbrains.org.objectweb.asm.Label;
039 import org.jetbrains.org.objectweb.asm.MethodVisitor;
040 import org.jetbrains.org.objectweb.asm.Type;
041 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
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.jet.codegen.JvmCodegenUtil.*;
049 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
050 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
051 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME;
052 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
053 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive;
054 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
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
218 public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
219 if (isDeclarationInsideInlineFunction(descriptor)) {
220 return ACC_PUBLIC;
221 }
222 return NO_FLAG_PACKAGE_PRIVATE;
223 }
224
225 public static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) {
226 //NB: constructor context couldn't be inline
227 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration();
228 if (parentDeclaration instanceof SimpleFunctionDescriptor &&
229 ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) {
230 return true;
231 }
232 return false;
233 }
234
235 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
236 if (descriptor instanceof PropertyAccessorDescriptor) {
237 return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
238 ? ACC_DEPRECATED
239 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
240 }
241 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
242 return ACC_DEPRECATED;
243 }
244 return 0;
245 }
246
247 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
248 if (!functionDescriptor.getValueParameters().isEmpty()
249 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
250 .getVarargElementType() != null) {
251 return ACC_VARARGS;
252 }
253 return 0;
254 }
255
256 @Nullable
257 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
258 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
259 if (isInterface(containingDeclaration)) {
260 return ACC_PUBLIC;
261 }
262 Visibility memberVisibility = memberDescriptor.getVisibility();
263 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
264 return ACC_PUBLIC;
265 }
266 if (isEnumEntry(memberDescriptor)) {
267 return NO_FLAG_PACKAGE_PRIVATE;
268 }
269 if (memberVisibility != Visibilities.PRIVATE) {
270 return null;
271 }
272 // the following code is only for PRIVATE visibility of member
273 if (memberDescriptor instanceof ConstructorDescriptor) {
274 if (isAnonymousObject(containingDeclaration)) {
275 return NO_FLAG_PACKAGE_PRIVATE;
276 }
277
278 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
279 if (kind == ClassKind.OBJECT) {
280 return NO_FLAG_PACKAGE_PRIVATE;
281 }
282 else if (kind == ClassKind.ENUM_ENTRY) {
283 return NO_FLAG_PACKAGE_PRIVATE;
284 }
285 else if (kind == ClassKind.ENUM_CLASS) {
286 //TODO: should be ACC_PRIVATE
287 // see http://youtrack.jetbrains.com/issue/KT-2680
288 return ACC_PROTECTED;
289 }
290 }
291 if (containingDeclaration instanceof PackageFragmentDescriptor) {
292 return ACC_PUBLIC;
293 }
294 return null;
295 }
296
297 @NotNull
298 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) {
299 JetType jetType = getSuperClass(traitDescriptor);
300 Type type = typeMapper.mapType(jetType);
301 if (type.getInternalName().equals("java/lang/Object")) {
302 return typeMapper.mapType(traitDescriptor.getDefaultType());
303 }
304 return type;
305 }
306
307 private static Type stringValueOfOrStringBuilderAppendType(Type type) {
308 int sort = type.getSort();
309 return sort == Type.OBJECT || sort == Type.ARRAY
310 ? AsmTypeConstants.OBJECT_TYPE
311 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
312 }
313
314 public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) {
315 InstructionAdapter iv = new InstructionAdapter(mv);
316 iv.anew(Type.getObjectType(exception));
317 iv.dup();
318 iv.aconst(message);
319 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
320 iv.athrow();
321 }
322
323 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
324 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
325
326 ClassifierDescriptor captureThis = closure.getCaptureThis();
327 if (captureThis != null) {
328 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
329 }
330
331 JetType captureReceiverType = closure.getCaptureReceiverType();
332 if (captureReceiverType != null) {
333 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
334 }
335
336 allFields.addAll(closure.getRecordedFields());
337 genClosureFields(allFields, v);
338 }
339
340 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
341 //noinspection PointlessBitwiseExpression
342 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
343 for (Pair<String, Type> field : allFields) {
344 builder.newField(null, access, field.first, field.second.getDescriptor(), null, null);
345 }
346 }
347
348 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) {
349 List<FieldInfo> result = new ArrayList<FieldInfo>();
350 for (Pair<String, Type> field : allFields) {
351 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first));
352 }
353 return result;
354 }
355
356 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
357 assert !info.isStatic();
358 Type fieldType = info.getFieldType();
359 iv.load(0, info.getOwnerType());//this
360 iv.load(index, fieldType); //param
361 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
362 index += fieldType.getSize();
363 return index;
364 }
365
366 public static void genStringBuilderConstructor(InstructionAdapter v) {
367 v.visitTypeInsn(NEW, "java/lang/StringBuilder");
368 v.dup();
369 v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
370 }
371
372 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
373 type = stringValueOfOrStringBuilderAppendType(type);
374 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
375 }
376
377 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
378 Type type = stringValueOfOrStringBuilderAppendType(receiverType);
379 receiver.put(type, v);
380 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
381 return StackValue.onStack(JAVA_STRING_TYPE);
382 }
383
384 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
385 if (type.getSort() == Type.ARRAY) {
386 Type elementType = correctElementType(type);
387 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
388 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
389 }
390 else {
391 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
392 }
393 }
394 else if (type.getSort() == Type.OBJECT) {
395 iv.invokevirtual("java/lang/Object", "hashCode", "()I");
396 }
397 else if (type.getSort() == Type.LONG) {
398 genLongHashCode(mv, iv);
399 }
400 else if (type.getSort() == Type.DOUBLE) {
401 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
402 genLongHashCode(mv, iv);
403 }
404 else if (type.getSort() == Type.FLOAT) {
405 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
406 }
407 else if (type.getSort() == Type.BOOLEAN) {
408 Label end = new Label();
409 iv.dup();
410 iv.ifeq(end);
411 iv.pop();
412 iv.iconst(1);
413 iv.mark(end);
414 }
415 else { // byte short char int
416 // do nothing
417 }
418 }
419
420 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
421 iv.dup2();
422 iv.iconst(32);
423 iv.ushr(Type.LONG_TYPE);
424 iv.xor(Type.LONG_TYPE);
425 mv.visitInsn(L2I);
426 }
427
428 static void genInvertBoolean(InstructionAdapter v) {
429 v.iconst(1);
430 v.xor(Type.INT_TYPE);
431 }
432
433 public static StackValue genEqualsForExpressionsOnStack(
434 InstructionAdapter v,
435 IElementType opToken,
436 Type leftType,
437 Type rightType
438 ) {
439 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
440 return StackValue.cmp(opToken, leftType);
441 }
442 else {
443 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
444 return StackValue.cmp(opToken, leftType);
445 }
446 else {
447 v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
448
449 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
450 genInvertBoolean(v);
451 }
452
453 return StackValue.onStack(Type.BOOLEAN_TYPE);
454 }
455 }
456 }
457
458 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
459 if (expectedType == Type.LONG_TYPE) {
460 v.lconst(myDelta);
461 }
462 else if (expectedType == Type.FLOAT_TYPE) {
463 v.fconst(myDelta);
464 }
465 else if (expectedType == Type.DOUBLE_TYPE) {
466 v.dconst(myDelta);
467 }
468 else {
469 v.iconst(myDelta);
470 v.add(Type.INT_TYPE);
471 StackValue.coerce(Type.INT_TYPE, expectedType, v);
472 return;
473 }
474 v.add(expectedType);
475 }
476
477 public static Type genNegate(Type expectedType, InstructionAdapter v) {
478 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
479 expectedType = Type.INT_TYPE;
480 }
481 v.neg(expectedType);
482 return expectedType;
483 }
484
485 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
486 if (stackTop.getSize() == 1) {
487 if (afterTop.getSize() == 1) {
488 v.swap();
489 } else {
490 v.dupX2();
491 v.pop();
492 }
493 } else {
494 if (afterTop.getSize() == 1) {
495 v.dup2X1();
496 } else {
497 v.dup2X2();
498 }
499 v.pop2();
500 }
501 }
502
503 public static void genNotNullAssertionsForParameters(
504 @NotNull InstructionAdapter v,
505 @NotNull GenerationState state,
506 @NotNull FunctionDescriptor descriptor,
507 @NotNull FrameMap frameMap
508 ) {
509 if (!state.isGenerateNotNullParamAssertions()) return;
510
511 // Private method is not accessible from other classes, no assertions needed
512 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
513
514 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
515 JetType type = parameter.getReturnType();
516 if (type == null || isNullableType(type)) continue;
517
518 int index = frameMap.getIndex(parameter);
519 Type asmType = state.getTypeMapper().mapType(type);
520 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
521 v.load(index, asmType);
522 v.visitLdcInsn(parameter.getName().asString());
523 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V");
524 }
525 }
526 }
527
528 public static void genNotNullAssertionForField(
529 @NotNull InstructionAdapter v,
530 @NotNull GenerationState state,
531 @NotNull PropertyDescriptor descriptor
532 ) {
533 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
534 }
535
536 public static void genNotNullAssertionForMethod(
537 @NotNull InstructionAdapter v,
538 @NotNull GenerationState state,
539 @NotNull ResolvedCall resolvedCall
540 ) {
541 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
542 if (descriptor instanceof ConstructorDescriptor) return;
543
544 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
545 }
546
547 private static void genNotNullAssertion(
548 @NotNull InstructionAdapter v,
549 @NotNull GenerationState state,
550 @NotNull CallableDescriptor descriptor,
551 @NotNull String assertMethodToCall
552 ) {
553 if (!state.isGenerateNotNullAssertions()) return;
554
555 if (!isDeclaredInJava(descriptor)) return;
556
557 JetType type = descriptor.getReturnType();
558 if (type == null || isNullableType(type)) return;
559
560 Type asmType = state.getTypeMapper().mapReturnType(descriptor);
561 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
562 v.dup();
563 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
564 v.visitLdcInsn(descriptor.getName().asString());
565 v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V");
566 }
567 }
568
569 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
570 CallableDescriptor descriptor = callableDescriptor;
571 while (true) {
572 if (descriptor instanceof JavaCallableMemberDescriptor) {
573 return true;
574 }
575 CallableDescriptor original = descriptor.getOriginal();
576 if (descriptor == original) break;
577 descriptor = original;
578 }
579 return false;
580 }
581
582 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
583 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
584 v.aconst(null);
585 }
586 else {
587 pushDefaultPrimitiveValueOnStack(type, v);
588 }
589 }
590
591 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
592 if (type.getSort() == Type.FLOAT) {
593 v.fconst(0);
594 }
595 else if (type.getSort() == Type.DOUBLE) {
596 v.dconst(0);
597 }
598 else if (type.getSort() == Type.LONG) {
599 v.lconst(0);
600 }
601 else {
602 v.iconst(0);
603 }
604 }
605
606 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
607 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS);
608 }
609
610 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
611 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
612 if (isDelegate || isExtensionProperty) {
613 return ACC_PRIVATE;
614 } else {
615 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE;
616 }
617 }
618
619 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
620 if (!propertyDescriptor.isVar() ) {
621 return propertyDescriptor;
622 } else {
623 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
624 }
625 }
626
627 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
628 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
629 return !propertyDescriptor.isVar() && !isExtensionProperty
630 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
631 && areBothAccessorDefault(propertyDescriptor)
632 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
633 }
634
635 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
636 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS);
637 }
638
639 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
640 return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
641 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
642 }
643
644 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
645 return accessorDescriptor == null || !accessorDescriptor.hasBody();
646 }
647
648 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) {
649 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
650 }
651
652 public static Type comparisonOperandType(Type left, Type right) {
653 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
654 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
655 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
656 return Type.INT_TYPE;
657 }
658
659 @NotNull
660 public static Type numberFunctionOperandType(@NotNull Type expectedType) {
661 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) {
662 return Type.INT_TYPE;
663 }
664 return expectedType;
665 }
666
667 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
668 if (type.getSize() == 2) {
669 v.pop2();
670 }
671 else {
672 v.pop();
673 }
674 }
675
676 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
677 if (type.getSize() == 2) {
678 v.dup2();
679 }
680 else {
681 v.dup();
682 }
683 }
684
685 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
686 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
687 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
688 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(),
689 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
690 kind.toString());
691 av.visitEnd();
692 }
693
694 @NotNull
695 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
696 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
697 }
698
699 @NotNull
700 public static String shortNameByAsmType(@NotNull Type type) {
701 String internalName = type.getInternalName();
702 int lastSlash = internalName.lastIndexOf('/');
703 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
704 }
705
706 @NotNull
707 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
708 return Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName());
709 }
710 }