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