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