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