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