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