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