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