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 (memberVisibility != Visibilities.PRIVATE) {
248 return null;
249 }
250 // the following code is only for PRIVATE visibility of member
251 if (isEnumEntry(memberDescriptor)) {
252 return NO_FLAG_PACKAGE_PRIVATE;
253 }
254 if (memberDescriptor instanceof ConstructorDescriptor) {
255 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
256 if (kind == ClassKind.OBJECT) {
257 return NO_FLAG_PACKAGE_PRIVATE;
258 }
259 else if (kind == ClassKind.ENUM_ENTRY) {
260 return NO_FLAG_PACKAGE_PRIVATE;
261 }
262 else if (kind == ClassKind.ENUM_CLASS) {
263 //TODO: should be ACC_PRIVATE
264 // see http://youtrack.jetbrains.com/issue/KT-2680
265 return ACC_PROTECTED;
266 }
267 }
268 if (containingDeclaration instanceof NamespaceDescriptor) {
269 return ACC_PUBLIC;
270 }
271 return null;
272 }
273
274 @NotNull
275 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) {
276 JetType jetType = getSuperClass(traitDescriptor);
277 Type type = typeMapper.mapType(jetType);
278 if (type.getInternalName().equals("java/lang/Object")) {
279 return typeMapper.mapType(traitDescriptor.getDefaultType());
280 }
281 return type;
282 }
283
284 private static Type stringValueOfOrStringBuilderAppendType(Type type) {
285 int sort = type.getSort();
286 return sort == Type.OBJECT || sort == Type.ARRAY
287 ? AsmTypeConstants.OBJECT_TYPE
288 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
289 }
290
291 public static void genThrow(MethodVisitor mv, String exception, String message) {
292 InstructionAdapter iv = new InstructionAdapter(mv);
293 iv.anew(Type.getObjectType(exception));
294 iv.dup();
295 iv.aconst(message);
296 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
297 iv.athrow();
298 }
299
300 public static void genMethodThrow(MethodVisitor mv, String exception, String message) {
301 mv.visitCode();
302 genThrow(mv, exception, message);
303 mv.visitMaxs(-1, -1);
304 mv.visitEnd();
305 }
306
307 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
308 ClassifierDescriptor captureThis = closure.getCaptureThis();
309 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
310 if (captureThis != null) {
311 v.newField(null, access, CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis).getDescriptor(), null,
312 null);
313 }
314
315 JetType captureReceiverType = closure.getCaptureReceiverType();
316 if (captureReceiverType != null) {
317 v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType).getDescriptor(),
318 null, null);
319 }
320
321 List<Pair<String, Type>> fields = closure.getRecordedFields();
322 for (Pair<String, Type> field : fields) {
323 v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
324 }
325 }
326
327 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
328 assert !info.isStatic();
329 Type fieldType = info.getFieldType();
330 iv.load(0, info.getOwnerType());//this
331 iv.load(index, fieldType); //param
332 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
333 index += fieldType.getSize();
334 return index;
335 }
336
337 public static void genStringBuilderConstructor(InstructionAdapter v) {
338 v.visitTypeInsn(NEW, "java/lang/StringBuilder");
339 v.dup();
340 v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
341 }
342
343 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
344 type = stringValueOfOrStringBuilderAppendType(type);
345 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
346 }
347
348 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
349 Type type = stringValueOfOrStringBuilderAppendType(receiverType);
350 receiver.put(type, v);
351 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
352 return StackValue.onStack(JAVA_STRING_TYPE);
353 }
354
355 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
356 if (type.getSort() == Type.ARRAY) {
357 Type elementType = correctElementType(type);
358 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
359 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
360 }
361 else {
362 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
363 }
364 }
365 else if (type.getSort() == Type.OBJECT) {
366 iv.invokevirtual("java/lang/Object", "hashCode", "()I");
367 }
368 else if (type.getSort() == Type.LONG) {
369 genLongHashCode(mv, iv);
370 }
371 else if (type.getSort() == Type.DOUBLE) {
372 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
373 genLongHashCode(mv, iv);
374 }
375 else if (type.getSort() == Type.FLOAT) {
376 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
377 }
378 else if (type.getSort() == Type.BOOLEAN) {
379 Label end = new Label();
380 iv.dup();
381 iv.ifeq(end);
382 iv.pop();
383 iv.iconst(1);
384 iv.mark(end);
385 }
386 else { // byte short char int
387 // do nothing
388 }
389 }
390
391 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
392 iv.dup2();
393 iv.iconst(32);
394 iv.ushr(Type.LONG_TYPE);
395 iv.xor(Type.LONG_TYPE);
396 mv.visitInsn(L2I);
397 }
398
399 static void genInvertBoolean(InstructionAdapter v) {
400 v.iconst(1);
401 v.xor(Type.INT_TYPE);
402 }
403
404 public static StackValue genEqualsForExpressionsOnStack(
405 InstructionAdapter v,
406 IElementType opToken,
407 Type leftType,
408 Type rightType
409 ) {
410 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
411 return StackValue.cmp(opToken, leftType);
412 }
413 else {
414 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
415 return StackValue.cmp(opToken, leftType);
416 }
417 else {
418 v.invokestatic("jet/runtime/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
419
420 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
421 genInvertBoolean(v);
422 }
423
424 return StackValue.onStack(Type.BOOLEAN_TYPE);
425 }
426 }
427 }
428
429 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
430 if (expectedType == Type.LONG_TYPE) {
431 v.lconst(myDelta);
432 }
433 else if (expectedType == Type.FLOAT_TYPE) {
434 v.fconst(myDelta);
435 }
436 else if (expectedType == Type.DOUBLE_TYPE) {
437 v.dconst(myDelta);
438 }
439 else {
440 v.iconst(myDelta);
441 v.add(Type.INT_TYPE);
442 StackValue.coerce(Type.INT_TYPE, expectedType, v);
443 return;
444 }
445 v.add(expectedType);
446 }
447
448 public static Type genNegate(Type expectedType, InstructionAdapter v) {
449 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
450 expectedType = Type.INT_TYPE;
451 }
452 v.neg(expectedType);
453 return expectedType;
454 }
455
456 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
457 if (stackTop.getSize() == 1) {
458 if (afterTop.getSize() == 1) {
459 v.swap();
460 } else {
461 v.dupX2();
462 v.pop();
463 }
464 } else {
465 if (afterTop.getSize() == 1) {
466 v.dup2X1();
467 } else {
468 v.dup2X2();
469 }
470 v.pop2();
471 }
472 }
473
474 public static void genNotNullAssertionsForParameters(
475 @NotNull InstructionAdapter v,
476 @NotNull GenerationState state,
477 @NotNull FunctionDescriptor descriptor,
478 @NotNull FrameMap frameMap
479 ) {
480 if (!state.isGenerateNotNullParamAssertions()) return;
481
482 // Private method is not accessible from other classes, no assertions needed
483 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
484
485 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
486 JetType type = parameter.getReturnType();
487 if (type == null || isNullableType(type)) continue;
488
489 int index = frameMap.getIndex(parameter);
490 Type asmType = state.getTypeMapper().mapReturnType(type);
491 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
492 v.load(index, asmType);
493 v.visitLdcInsn(parameter.getName().asString());
494 v.invokestatic("jet/runtime/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V");
495 }
496 }
497 }
498
499 public static void genNotNullAssertionForField(
500 @NotNull InstructionAdapter v,
501 @NotNull GenerationState state,
502 @NotNull PropertyDescriptor descriptor
503 ) {
504 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
505 }
506
507 public static void genNotNullAssertionForMethod(
508 @NotNull InstructionAdapter v,
509 @NotNull GenerationState state,
510 @NotNull ResolvedCall resolvedCall
511 ) {
512 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
513 if (descriptor instanceof ConstructorDescriptor) return;
514
515 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
516 }
517
518 private static void genNotNullAssertion(
519 @NotNull InstructionAdapter v,
520 @NotNull GenerationState state,
521 @NotNull CallableDescriptor descriptor,
522 @NotNull String assertMethodToCall
523 ) {
524 if (!state.isGenerateNotNullAssertions()) return;
525
526 if (!isDeclaredInJava(descriptor)) return;
527
528 JetType type = descriptor.getReturnType();
529 if (type == null || isNullableType(type)) return;
530
531 Type asmType = state.getTypeMapper().mapReturnType(type);
532 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
533 v.dup();
534 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
535 v.visitLdcInsn(descriptor.getName().asString());
536 v.invokestatic("jet/runtime/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V");
537 }
538 }
539
540 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
541 CallableDescriptor descriptor = callableDescriptor;
542 while (true) {
543 if (descriptor instanceof JavaCallableMemberDescriptor) {
544 return true;
545 }
546 CallableDescriptor original = descriptor.getOriginal();
547 if (descriptor == original) break;
548 descriptor = original;
549 }
550 return false;
551 }
552
553 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
554 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
555 v.aconst(null);
556 }
557 else {
558 pushDefaultPrimitiveValueOnStack(type, v);
559 }
560 }
561
562 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
563 if (type.getSort() == Type.FLOAT) {
564 v.fconst(0);
565 }
566 else if (type.getSort() == Type.DOUBLE) {
567 v.dconst(0);
568 }
569 else if (type.getSort() == Type.LONG) {
570 v.lconst(0);
571 }
572 else {
573 v.iconst(0);
574 }
575 }
576
577 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
578 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS);
579 }
580
581 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
582 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
583 if (isDelegate || isExtensionProperty) {
584 return ACC_PRIVATE;
585 } else {
586 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE;
587 }
588 }
589
590 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
591 if (!propertyDescriptor.isVar() ) {
592 return propertyDescriptor;
593 } else {
594 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
595 }
596 }
597
598 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
599 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
600 return !propertyDescriptor.isVar() && !isExtensionProperty
601 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
602 && areBothAccessorDefault(propertyDescriptor)
603 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
604 }
605
606 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
607 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS);
608 }
609
610 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
611 return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
612 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
613 }
614
615 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
616 return accessorDescriptor == null || !accessorDescriptor.hasBody();
617 }
618
619 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) {
620 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
621 }
622
623 public static Type comparisonOperandType(Type left, Type right) {
624 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
625 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
626 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
627 return Type.INT_TYPE;
628 }
629
630 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
631 if (type.getSize() == 2) {
632 v.pop2();
633 }
634 else {
635 v.pop();
636 }
637 }
638
639 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
640 if (type.getSize() == 2) {
641 v.dup2();
642 }
643 else {
644 v.dup();
645 }
646 }
647
648 @NotNull
649 public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
650 return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
651 }
652
653 @NotNull
654 public static String shortNameByAsmType(@NotNull Type type) {
655 String internalName = type.getInternalName();
656 int lastSlash = internalName.lastIndexOf('/');
657 return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
658 }
659
660 @NotNull
661 public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
662 return Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName());
663 }
664 }