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 NO_FLAG_PACKAGE_PRIVATE;
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 return isNonCompanionObject(propertyDescriptor.getContainingDeclaration()) ||
758 isPropertyWithBackingFieldInOuterClass(propertyDescriptor) ||
759 isInterfaceCompanionObject(propertyDescriptor.getContainingDeclaration());
760 }
761
762 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
763 return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
764 isCompanionObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
765 }
766
767 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
768 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
769 if (isDelegate || isExtensionProperty) {
770 return ACC_PRIVATE;
771 }
772 else {
773 return areBothAccessorDefault(propertyDescriptor)
774 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
775 : ACC_PRIVATE;
776 }
777 }
778
779 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
780 if (!propertyDescriptor.isVar()) {
781 return propertyDescriptor;
782 }
783 else {
784 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
785 }
786 }
787
788 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
789 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
790 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
791 return !propertyDescriptor.isVar()
792 && !isExtensionProperty
793 && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration())
794 && areBothAccessorDefault(propertyDescriptor)
795 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
796 }
797
798 public static boolean isCompanionObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor companionObject) {
799 DeclarationDescriptor containingClass = companionObject.getContainingDeclaration();
800 return isCompanionObject(companionObject) && (isClass(containingClass) || isEnumClass(containingClass));
801 }
802
803 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
804 return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
805 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
806 }
807
808 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
809 return accessorDescriptor == null || !accessorDescriptor.hasBody();
810 }
811
812 public static Type comparisonOperandType(Type left, Type right) {
813 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
814 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
815 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
816 return Type.INT_TYPE;
817 }
818
819 @NotNull
820 public static Type numberFunctionOperandType(@NotNull Type expectedType) {
821 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
822 return Type.INT_TYPE;
823 }
824 return expectedType;
825 }
826
827 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
828 if (type.getSize() == 2) {
829 v.visitInsn(Opcodes.POP2);
830 }
831 else {
832 v.visitInsn(Opcodes.POP);
833 }
834 }
835
836 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
837 int size = type.getSize();
838 if (size == 2) {
839 v.dup2();
840 }
841 else if (size == 1) {
842 v.dup();
843 }
844 else {
845 throw new UnsupportedOperationException();
846 }
847 }
848
849 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull GenerationState state) {
850 AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(KOTLIN_SYNTHETIC_CLASS), true);
851 JvmCodegenUtil.writeAbiVersion(av);
852 JvmCodegenUtil.writeModuleName(av, state);
853 av.visitEnd();
854 }
855
856 public static void writeAnnotationData(
857 @NotNull AnnotationVisitor av,
858 @NotNull DescriptorSerializer serializer,
859 @NotNull MessageLite message
860 ) {
861 byte[] bytes = serializer.serialize(message);
862
863 JvmCodegenUtil.writeAbiVersion(av);
864 AnnotationVisitor data = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
865 for (String string : BitEncoding.encodeBytes(bytes)) {
866 data.visit(null, string);
867 }
868 data.visitEnd();
869 AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.STRINGS_FIELD_NAME);
870 for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
871 strings.visit(null, string);
872 }
873 strings.visitEnd();
874 }
875
876 @NotNull
877 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
878 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
879 }
880
881 @NotNull
882 public static String shortNameByAsmType(@NotNull Type type) {
883 String internalName = type.getInternalName();
884 int lastSlash = internalName.lastIndexOf('/');
885 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
886 }
887
888 @NotNull
889 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
890 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
891 }
892
893 @NotNull
894 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
895 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
896 }
897
898 @NotNull
899 public static String getSimpleInternalName(@NotNull String internalName) {
900 int lastSlash = internalName.lastIndexOf('/');
901 if (lastSlash >= 0) {
902 return internalName.substring(lastSlash + 1);
903 }
904 else {
905 return internalName;
906 }
907 }
908
909 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
910 if (isPrimitive(type)) {
911 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
912 }
913 else {
914 v.aconst(type);
915 }
916 }
917
918 public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
919 v.invokestatic(REFLECTION, "getOrCreateKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
920 }
921
922 public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
923 v.invokestatic(REFLECTION, "getOrCreateKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
924 }
925
926 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
927 OwnerKind kind = context.getContextKind();
928 //Trait always should have this descriptor
929 return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
930 }
931 }