001 /*
002 * Copyright 2010-2013 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.jet.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 org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
026 import org.jetbrains.jet.codegen.binding.CodegenBinding;
027 import org.jetbrains.jet.codegen.context.CodegenContext;
028 import org.jetbrains.jet.codegen.state.GenerationState;
029 import org.jetbrains.jet.codegen.state.JetTypeMapper;
030 import org.jetbrains.jet.lang.descriptors.*;
031 import org.jetbrains.jet.lang.psi.JetFile;
032 import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
033 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
034 import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage;
035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.jet.lang.resolve.java.*;
037 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaCallableMemberDescriptor;
038 import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
039 import org.jetbrains.jet.lang.resolve.name.FqName;
040 import org.jetbrains.jet.lang.types.JetType;
041 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
042 import org.jetbrains.jet.lexer.JetTokens;
043 import org.jetbrains.org.objectweb.asm.*;
044 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
045 import org.jetbrains.org.objectweb.asm.commons.Method;
046
047 import java.util.ArrayList;
048 import java.util.List;
049 import java.util.Map;
050 import java.util.Set;
051
052 import static org.jetbrains.jet.codegen.JvmCodegenUtil.isInterface;
053 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
054 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
055 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
056 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME;
057 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
058 import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
059 import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive;
060 import static org.jetbrains.jet.lang.types.TypeUtils.isNullableType;
061 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
062
063 public class AsmUtil {
064 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet(
065 KotlinBuiltIns.getInstance().getByte(),
066 KotlinBuiltIns.getInstance().getShort(),
067 KotlinBuiltIns.getInstance().getInt(),
068 KotlinBuiltIns.getInstance().getLong(),
069 KotlinBuiltIns.getInstance().getFloat(),
070 KotlinBuiltIns.getInstance().getDouble(),
071 KotlinBuiltIns.getInstance().getChar()
072 );
073
074 private static final Set<Type> STRING_BUILDER_OBJECT_APPEND_ARG_TYPES = Sets.newHashSet(
075 getType(String.class),
076 getType(StringBuffer.class),
077 getType(CharSequence.class)
078 );
079
080 private static final int NO_FLAG_LOCAL = 0;
081 public static final int NO_FLAG_PACKAGE_PRIVATE = 0;
082
083 @NotNull
084 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
085 .put(Visibilities.PRIVATE, 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 = asmTypeForPrimitive(primitiveType);
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 = primitiveTypeByBoxedType.get(boxedType);
125 if (primitiveType == null) {
126 throw new UnsupportedOperationException("Unboxing: " + boxedType);
127 }
128 return primitiveType;
129 }
130
131 public static boolean isIntPrimitive(Type type) {
132 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
133 }
134
135 public static boolean isNumberPrimitive(Type type) {
136 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
137 }
138
139 public static boolean isPrimitive(Type type) {
140 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
141 }
142
143 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
144 if (!(descriptor instanceof ClassDescriptor)) {
145 return false;
146 }
147 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor);
148 }
149
150 public static Type correctElementType(Type type) {
151 String internalName = type.getInternalName();
152 assert internalName.charAt(0) == '[';
153 return Type.getType(internalName.substring(1));
154 }
155
156 @NotNull
157 public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) {
158 return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
159 }
160
161 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
162 return (functionDescriptor.getModality() == Modality.ABSTRACT
163 || isInterface(functionDescriptor.getContainingDeclaration()))
164 && !isStaticMethod(kind, functionDescriptor);
165 }
166
167 public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) {
168 return isStaticKind(kind) ||
169 JetTypeMapper.isAccessor(functionDescriptor) ||
170 AnnotationsPackage.isPlatformStaticInObject(functionDescriptor);
171 }
172
173 public static boolean isStaticKind(OwnerKind kind) {
174 return kind == OwnerKind.PACKAGE || kind == OwnerKind.TRAIT_IMPL;
175 }
176
177 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
178 int flags = getCommonCallableFlags(functionDescriptor);
179
180 for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
181 if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) {
182 flags |= flagAnnotation.getJvmFlag();
183 }
184 }
185
186 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
187 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
188 if (!(containingDeclaration instanceof ClassDescriptor) ||
189 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) {
190 flags |= ACC_FINAL;
191 }
192 }
193
194 if (isStaticMethod(kind, functionDescriptor)) {
195 flags |= ACC_STATIC;
196 }
197
198 if (isAbstractMethod(functionDescriptor, kind)) {
199 flags |= ACC_ABSTRACT;
200 }
201
202 if (JetTypeMapper.isAccessor(functionDescriptor)) {
203 flags |= ACC_SYNTHETIC;
204 }
205
206 return flags;
207 }
208
209 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
210 int flags = getVisibilityAccessFlag(functionDescriptor);
211 flags |= getVarargsFlag(functionDescriptor);
212 flags |= getDeprecatedAccessFlag(functionDescriptor);
213 return flags;
214 }
215
216 //TODO: move mapping logic to front-end java
217 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
218 Integer specialCase = specialCaseVisibility(descriptor);
219 if (specialCase != null) {
220 return specialCase;
221 }
222 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility());
223 if (defaultMapping == null) {
224 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend: " + descriptor);
225 }
226 return defaultMapping;
227 }
228
229 /*
230 Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
231 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
232 Classes in byte code should be public or package private
233 */
234 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) {
235 if (DescriptorUtils.isTopLevelDeclaration(descriptor) ||
236 descriptor.getVisibility() == Visibilities.PUBLIC ||
237 descriptor.getVisibility() == Visibilities.INTERNAL) {
238 return ACC_PUBLIC;
239 }
240 return NO_FLAG_PACKAGE_PRIVATE;
241 }
242
243 public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
244 if (isDeclarationInsideInlineFunction(descriptor)) {
245 return ACC_PUBLIC;
246 }
247 return NO_FLAG_PACKAGE_PRIVATE;
248 }
249
250 private static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) {
251 //NB: constructor context couldn't be inline
252 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration();
253 if (parentDeclaration instanceof SimpleFunctionDescriptor &&
254 ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) {
255 return true;
256 }
257 return false;
258 }
259
260 public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
261 return getVisibilityAccessFlag(innerClass) |
262 innerAccessFlagsForModalityAndKind(innerClass) |
263 (innerClass.isInner() ? 0 : ACC_STATIC);
264 }
265
266 private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) {
267 switch (innerClass.getKind()) {
268 case TRAIT:
269 return ACC_ABSTRACT | ACC_INTERFACE;
270 case ENUM_CLASS:
271 return ACC_FINAL | ACC_ENUM;
272 case ANNOTATION_CLASS:
273 return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE;
274 default:
275 if (innerClass.getModality() == Modality.FINAL) {
276 return ACC_FINAL;
277 }
278 else if (innerClass.getModality() == Modality.ABSTRACT) {
279 return ACC_ABSTRACT;
280 }
281 }
282 return 0;
283 }
284
285 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
286 if (descriptor instanceof PropertyAccessorDescriptor) {
287 return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
288 ? ACC_DEPRECATED
289 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
290 }
291 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
292 return ACC_DEPRECATED;
293 }
294 return 0;
295 }
296
297 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
298 if (!functionDescriptor.getValueParameters().isEmpty()
299 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
300 .getVarargElementType() != null) {
301 return ACC_VARARGS;
302 }
303 return 0;
304 }
305
306 @Nullable
307 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
308 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
309 if (isInterface(containingDeclaration)) {
310 return ACC_PUBLIC;
311 }
312 Visibility memberVisibility = memberDescriptor.getVisibility();
313 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
314 return ACC_PUBLIC;
315 }
316 if (isEnumEntry(memberDescriptor)) {
317 return NO_FLAG_PACKAGE_PRIVATE;
318 }
319 if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
320 return NO_FLAG_PACKAGE_PRIVATE;
321 }
322 if (memberVisibility != Visibilities.PRIVATE) {
323 return null;
324 }
325 // the following code is only for PRIVATE visibility of member
326 if (memberDescriptor instanceof ConstructorDescriptor) {
327 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
328 if (kind == ClassKind.OBJECT || kind == ClassKind.ENUM_ENTRY) {
329 return NO_FLAG_PACKAGE_PRIVATE;
330 }
331 if (kind == ClassKind.ENUM_CLASS) {
332 //TODO: should be ACC_PRIVATE
333 // see http://youtrack.jetbrains.com/issue/KT-2680
334 return ACC_PROTECTED;
335 }
336 }
337 if (containingDeclaration instanceof PackageFragmentDescriptor) {
338 return ACC_PUBLIC;
339 }
340 return null;
341 }
342
343 private static Type stringValueOfType(Type type) {
344 int sort = type.getSort();
345 return sort == Type.OBJECT || sort == Type.ARRAY
346 ? AsmTypeConstants.OBJECT_TYPE
347 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
348 }
349
350 private static Type stringBuilderAppendType(Type type) {
351 switch (type.getSort()) {
352 case Type.OBJECT:
353 return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : AsmTypeConstants.OBJECT_TYPE;
354 case Type.ARRAY:
355 return AsmTypeConstants.OBJECT_TYPE;
356 case Type.BYTE:
357 case Type.SHORT:
358 return Type.INT_TYPE;
359 default:
360 return type;
361 }
362 }
363
364 public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) {
365 v.anew(Type.getObjectType(exception));
366 v.dup();
367 if (message != null) {
368 v.aconst(message);
369 v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false);
370 }
371 else {
372 v.invokespecial(exception, "<init>", "()V", false);
373 }
374 v.athrow();
375 }
376
377 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
378 List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
379
380 ClassifierDescriptor captureThis = closure.getCaptureThis();
381 if (captureThis != null) {
382 allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
383 }
384
385 JetType captureReceiverType = closure.getCaptureReceiverType();
386 if (captureReceiverType != null) {
387 allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
388 }
389
390 allFields.addAll(closure.getRecordedFields());
391 genClosureFields(allFields, v);
392 }
393
394 public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
395 //noinspection PointlessBitwiseExpression
396 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
397 for (Pair<String, Type> field : allFields) {
398 builder.newField(NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null);
399 }
400 }
401
402 public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) {
403 List<FieldInfo> result = new ArrayList<FieldInfo>();
404 for (Pair<String, Type> field : allFields) {
405 result.add(FieldInfo.createForHiddenField(owner, field.second, field.first));
406 }
407 return result;
408 }
409
410 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
411 assert !info.isStatic();
412 Type fieldType = info.getFieldType();
413 iv.load(0, info.getOwnerType());//this
414 iv.load(index, fieldType); //param
415 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
416 index += fieldType.getSize();
417 return index;
418 }
419
420 public static void genStringBuilderConstructor(InstructionAdapter v) {
421 v.visitTypeInsn(NEW, "java/lang/StringBuilder");
422 v.dup();
423 v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false);
424 }
425
426 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
427 type = stringBuilderAppendType(type);
428 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false);
429 }
430
431 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
432 Type type = stringValueOfType(receiverType);
433 receiver.put(type, v);
434 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false);
435 return StackValue.onStack(JAVA_STRING_TYPE);
436 }
437
438 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
439 if (type.getSort() == Type.ARRAY) {
440 Type elementType = correctElementType(type);
441 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
442 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false);
443 }
444 else {
445 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false);
446 }
447 }
448 else if (type.getSort() == Type.OBJECT) {
449 iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
450 }
451 else if (type.getSort() == Type.LONG) {
452 genLongHashCode(mv, iv);
453 }
454 else if (type.getSort() == Type.DOUBLE) {
455 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
456 genLongHashCode(mv, iv);
457 }
458 else if (type.getSort() == Type.FLOAT) {
459 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
460 }
461 else if (type.getSort() == Type.BOOLEAN) {
462 Label end = new Label();
463 iv.dup();
464 iv.ifeq(end);
465 iv.pop();
466 iv.iconst(1);
467 iv.mark(end);
468 }
469 else { // byte short char int
470 // do nothing
471 }
472 }
473
474 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
475 iv.dup2();
476 iv.iconst(32);
477 iv.ushr(Type.LONG_TYPE);
478 iv.xor(Type.LONG_TYPE);
479 mv.visitInsn(L2I);
480 }
481
482 static void genInvertBoolean(InstructionAdapter v) {
483 v.iconst(1);
484 v.xor(Type.INT_TYPE);
485 }
486
487 public static StackValue genEqualsForExpressionsOnStack(
488 InstructionAdapter v,
489 IElementType opToken,
490 Type leftType,
491 Type rightType
492 ) {
493 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
494 return StackValue.cmp(opToken, leftType);
495 }
496 else {
497 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
498 return StackValue.cmp(opToken, leftType);
499 }
500 else {
501 v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
502
503 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
504 genInvertBoolean(v);
505 }
506
507 return StackValue.onStack(Type.BOOLEAN_TYPE);
508 }
509 }
510 }
511
512 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
513 if (expectedType == Type.LONG_TYPE) {
514 v.lconst(myDelta);
515 }
516 else if (expectedType == Type.FLOAT_TYPE) {
517 v.fconst(myDelta);
518 }
519 else if (expectedType == Type.DOUBLE_TYPE) {
520 v.dconst(myDelta);
521 }
522 else {
523 v.iconst(myDelta);
524 v.add(Type.INT_TYPE);
525 StackValue.coerce(Type.INT_TYPE, expectedType, v);
526 return;
527 }
528 v.add(expectedType);
529 }
530
531 public static Type genNegate(Type expectedType, InstructionAdapter v) {
532 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
533 expectedType = Type.INT_TYPE;
534 }
535 v.neg(expectedType);
536 return expectedType;
537 }
538
539 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
540 if (stackTop.getSize() == 1) {
541 if (afterTop.getSize() == 1) {
542 v.swap();
543 }
544 else {
545 v.dupX2();
546 v.pop();
547 }
548 }
549 else {
550 if (afterTop.getSize() == 1) {
551 v.dup2X1();
552 }
553 else {
554 v.dup2X2();
555 }
556 v.pop2();
557 }
558 }
559
560 public static void genNotNullAssertionsForParameters(
561 @NotNull InstructionAdapter v,
562 @NotNull GenerationState state,
563 @NotNull FunctionDescriptor descriptor,
564 @NotNull FrameMap frameMap
565 ) {
566 if (!state.isParamAssertionsEnabled()) return;
567
568 // Private method is not accessible from other classes, no assertions needed
569 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
570
571 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
572 JetType type = parameter.getReturnType();
573 if (type == null || isNullableType(type)) continue;
574
575 int index = frameMap.getIndex(parameter);
576 Type asmType = state.getTypeMapper().mapType(type);
577 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
578 v.load(index, asmType);
579 v.visitLdcInsn(parameter.getName().asString());
580 v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull",
581 "(Ljava/lang/Object;Ljava/lang/String;)V", false);
582 }
583 }
584 }
585
586 public static void genNotNullAssertionForField(
587 @NotNull InstructionAdapter v,
588 @NotNull GenerationState state,
589 @NotNull PropertyDescriptor descriptor
590 ) {
591 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
592 }
593
594 public static void genNotNullAssertionForMethod(
595 @NotNull InstructionAdapter v,
596 @NotNull GenerationState state,
597 @NotNull ResolvedCall resolvedCall
598 ) {
599 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
600 if (descriptor instanceof ConstructorDescriptor) return;
601
602 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
603 }
604
605 private static void genNotNullAssertion(
606 @NotNull InstructionAdapter v,
607 @NotNull GenerationState state,
608 @NotNull CallableDescriptor descriptor,
609 @NotNull String assertMethodToCall
610 ) {
611 if (!state.isCallAssertionsEnabled()) return;
612
613 if (!isDeclaredInJava(descriptor)) return;
614
615 JetType type = descriptor.getReturnType();
616 if (type == null || isNullableType(type)) return;
617
618 Type asmType = state.getTypeMapper().mapReturnType(descriptor);
619 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
620 v.dup();
621 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
622 v.visitLdcInsn(descriptor.getName().asString());
623 v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall,
624 "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false);
625 }
626 }
627
628 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
629 CallableDescriptor descriptor = callableDescriptor;
630 while (true) {
631 if (descriptor instanceof JavaCallableMemberDescriptor) {
632 return true;
633 }
634 CallableDescriptor original = descriptor.getOriginal();
635 if (descriptor == original) break;
636 descriptor = original;
637 }
638 return false;
639 }
640
641 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
642 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
643 v.aconst(null);
644 }
645 else {
646 pushDefaultPrimitiveValueOnStack(type, v);
647 }
648 }
649
650 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
651 if (type.getSort() == Type.FLOAT) {
652 v.fconst(0);
653 }
654 else if (type.getSort() == Type.DOUBLE) {
655 v.dconst(0);
656 }
657 else if (type.getSort() == Type.LONG) {
658 v.lconst(0);
659 }
660 else {
661 v.iconst(0);
662 }
663 }
664
665 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
666 return isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
667 }
668
669 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
670 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
671 if (isDelegate || isExtensionProperty) {
672 return ACC_PRIVATE;
673 }
674 else {
675 return areBothAccessorDefault(propertyDescriptor)
676 ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
677 : ACC_PRIVATE;
678 }
679 }
680
681 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
682 if (!propertyDescriptor.isVar()) {
683 return propertyDescriptor;
684 }
685 else {
686 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
687 }
688 }
689
690 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
691 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
692 DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
693 return !propertyDescriptor.isVar()
694 && !isExtensionProperty
695 && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration())
696 && areBothAccessorDefault(propertyDescriptor)
697 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
698 }
699
700 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
701 DeclarationDescriptor containingClass = classObject.getContainingDeclaration();
702 return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass));
703 }
704
705 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
706 return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
707 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
708 }
709
710 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
711 return accessorDescriptor == null || !accessorDescriptor.hasBody();
712 }
713
714 public static Type comparisonOperandType(Type left, Type right) {
715 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
716 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
717 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
718 return Type.INT_TYPE;
719 }
720
721 @NotNull
722 public static Type numberFunctionOperandType(@NotNull Type expectedType) {
723 if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) {
724 return Type.INT_TYPE;
725 }
726 return expectedType;
727 }
728
729 public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
730 if (type.getSize() == 2) {
731 v.visitInsn(Opcodes.POP2);
732 }
733 else {
734 v.visitInsn(Opcodes.POP);
735 }
736 }
737
738 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
739 if (type.getSize() == 2) {
740 v.dup2();
741 }
742 else {
743 v.dup();
744 }
745 }
746
747 public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
748 AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
749 av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
750 av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(),
751 Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
752 kind.toString());
753 av.visitEnd();
754 }
755
756 @NotNull
757 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
758 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
759 }
760
761 @NotNull
762 public static String shortNameByAsmType(@NotNull Type type) {
763 String internalName = type.getInternalName();
764 int lastSlash = internalName.lastIndexOf('/');
765 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
766 }
767
768 @NotNull
769 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
770 return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
771 }
772
773 @NotNull
774 public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
775 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
776 }
777
778 public static void writeOuterClassAndEnclosingMethod(
779 @NotNull ClassDescriptor descriptor,
780 @NotNull DeclarationDescriptor originalDescriptor,
781 @NotNull JetTypeMapper typeMapper,
782 @NotNull ClassBuilder v
783 ) {
784 String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper);
785 FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
786
787 if (function != null) {
788 Method method = typeMapper.mapSignature(function).getAsmMethod();
789 v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
790 }
791 else {
792 v.visitOuterClass(outerClassName, null, null);
793 }
794 }
795
796 @NotNull
797 private static String getOuterClassName(
798 @NotNull ClassDescriptor classDescriptor,
799 @NotNull DeclarationDescriptor originalDescriptor,
800 @NotNull JetTypeMapper typeMapper
801 ) {
802 DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
803 while (container != null) {
804 if (container instanceof ClassDescriptor) {
805 return typeMapper.mapClass((ClassDescriptor) container).getInternalName();
806 }
807 else if (CodegenBinding.isLocalFunOrLambda(container)) {
808 ClassDescriptor descriptor =
809 CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container);
810 return typeMapper.mapClass(descriptor).getInternalName();
811 }
812
813 container = container.getContainingDeclaration();
814 }
815
816 JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor);
817 assert containingFile != null : "Containing file should be present for " + classDescriptor;
818 return PackagePartClassUtils.getPackagePartInternalName(containingFile);
819 }
820
821 public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
822 if (isPrimitive(type)) {
823 v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
824 }
825 else {
826 v.aconst(type);
827 }
828 }
829
830 public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
831 OwnerKind kind = context.getContextKind();
832 //Trait always should have this descriptor
833 return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1;
834 }
835 }