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.JvmAbi;
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.types.JetType;
041 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
042 import org.jetbrains.jet.lexer.JetTokens;
043
044 import java.util.List;
045 import java.util.Map;
046 import java.util.Set;
047
048 import static org.jetbrains.asm4.Opcodes.*;
049 import static org.jetbrains.jet.codegen.CodegenUtil.*;
050 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
051 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
052
053 public class AsmUtil {
054 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet(
055 KotlinBuiltIns.getInstance().getByte(),
056 KotlinBuiltIns.getInstance().getShort(),
057 KotlinBuiltIns.getInstance().getInt(),
058 KotlinBuiltIns.getInstance().getLong(),
059 KotlinBuiltIns.getInstance().getFloat(),
060 KotlinBuiltIns.getInstance().getDouble(),
061 KotlinBuiltIns.getInstance().getChar()
062 );
063
064 private static final int NO_FLAG_LOCAL = 0;
065 public static final int NO_FLAG_PACKAGE_PRIVATE = 0;
066
067 @NotNull
068 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
069 .put(Visibilities.PRIVATE, ACC_PRIVATE)
070 .put(Visibilities.PROTECTED, ACC_PROTECTED)
071 .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED)
072 .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED)
073 .put(Visibilities.PUBLIC, ACC_PUBLIC)
074 .put(Visibilities.INTERNAL, ACC_PUBLIC)
075 .put(Visibilities.LOCAL, NO_FLAG_LOCAL)
076 .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE)
077 .build();
078
079 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0";
080 public static final String CAPTURED_THIS_FIELD = "this$0";
081
082 private static final String STUB_EXCEPTION = "java/lang/RuntimeException";
083 private static final String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath";
084
085 private AsmUtil() {
086 }
087
088 public static Type boxType(Type asmType) {
089 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByAsmType(asmType);
090 if (jvmPrimitiveType != null) {
091 return jvmPrimitiveType.getWrapper().getAsmType();
092 }
093 else {
094 return asmType;
095 }
096 }
097
098 public static boolean isIntPrimitive(Type type) {
099 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
100 }
101
102 public static boolean isNumberPrimitive(Type type) {
103 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
104 }
105
106 public static boolean isPrimitive(Type type) {
107 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
108 }
109
110 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
111 if (!(descriptor instanceof ClassDescriptor)) {
112 return false;
113 }
114 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor);
115 }
116
117 public static Type correctElementType(Type type) {
118 String internalName = type.getInternalName();
119 assert internalName.charAt(0) == '[';
120 return Type.getType(internalName.substring(1));
121 }
122
123 public static Type unboxType(Type type) {
124 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByWrapperAsmType(type);
125 if (jvmPrimitiveType != null) {
126 return jvmPrimitiveType.getAsmType();
127 }
128 else {
129 throw new UnsupportedOperationException("Unboxing: " + type);
130 }
131 }
132
133 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
134 return (functionDescriptor.getModality() == Modality.ABSTRACT
135 || isInterface(functionDescriptor.getContainingDeclaration()))
136 && !isStaticMethod(kind, functionDescriptor);
137 }
138
139 public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) {
140 return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor);
141 }
142
143 public static boolean isStatic(OwnerKind kind) {
144 return kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.TRAIT_IMPL;
145 }
146
147 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
148 int flags = getCommonCallableFlags(functionDescriptor);
149
150 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
151 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
152 if (!(containingDeclaration instanceof ClassDescriptor) ||
153 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) {
154 flags |= ACC_FINAL;
155 }
156 }
157
158 if (isStaticMethod(kind, functionDescriptor)) {
159 flags |= ACC_STATIC;
160 }
161
162 if (isAbstractMethod(functionDescriptor, kind)) {
163 flags |= ACC_ABSTRACT;
164 }
165
166 if (JetTypeMapper.isAccessor(functionDescriptor)) {
167 flags |= ACC_SYNTHETIC;
168 }
169
170 return flags;
171 }
172
173 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
174 int flags = getVisibilityAccessFlag(functionDescriptor);
175 flags |= getVarargsFlag(functionDescriptor);
176 flags |= getDeprecatedAccessFlag(functionDescriptor);
177 return flags;
178 }
179
180 //TODO: move mapping logic to front-end java
181 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
182 Integer specialCase = specialCaseVisibility(descriptor);
183 if (specialCase != null) {
184 return specialCase;
185 }
186 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility());
187 if (defaultMapping == null) {
188 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend.");
189 }
190 return defaultMapping;
191 }
192
193 /*
194 Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
195 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
196 Classes in byte code should be public or package private
197 */
198 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) {
199 if (DescriptorUtils.isTopLevelDeclaration(descriptor) ||
200 descriptor.getVisibility() == Visibilities.PUBLIC ||
201 descriptor.getVisibility() == Visibilities.INTERNAL) {
202 return ACC_PUBLIC;
203 }
204 return NO_FLAG_PACKAGE_PRIVATE;
205 }
206
207 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
208 if (descriptor instanceof PropertyAccessorDescriptor) {
209 return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
210 ? ACC_DEPRECATED
211 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
212 }
213 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
214 return ACC_DEPRECATED;
215 }
216 return 0;
217 }
218
219 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
220 if (!functionDescriptor.getValueParameters().isEmpty()
221 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
222 .getVarargElementType() != null) {
223 return ACC_VARARGS;
224 }
225 return 0;
226 }
227
228 @Nullable
229 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
230 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
231 if (isInterface(containingDeclaration)) {
232 return ACC_PUBLIC;
233 }
234 Visibility memberVisibility = memberDescriptor.getVisibility();
235 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
236 return ACC_PUBLIC;
237 }
238 if (memberVisibility != Visibilities.PRIVATE) {
239 return null;
240 }
241 // the following code is only for PRIVATE visibility of member
242 if (isEnumEntry(memberDescriptor)) {
243 return NO_FLAG_PACKAGE_PRIVATE;
244 }
245 if (memberDescriptor instanceof ConstructorDescriptor) {
246 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
247 if (kind == ClassKind.OBJECT) {
248 return NO_FLAG_PACKAGE_PRIVATE;
249 }
250 else if (kind == ClassKind.ENUM_ENTRY) {
251 return NO_FLAG_PACKAGE_PRIVATE;
252 }
253 else if (kind == ClassKind.ENUM_CLASS) {
254 //TODO: should be ACC_PRIVATE
255 // see http://youtrack.jetbrains.com/issue/KT-2680
256 return ACC_PROTECTED;
257 }
258 }
259 if (containingDeclaration instanceof NamespaceDescriptor) {
260 return ACC_PUBLIC;
261 }
262 return null;
263 }
264
265 @NotNull
266 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) {
267 JetType jetType = getSuperClass(traitDescriptor);
268 Type type = typeMapper.mapType(jetType);
269 if (type.getInternalName().equals("java/lang/Object")) {
270 return typeMapper.mapType(traitDescriptor.getDefaultType());
271 }
272 return type;
273 }
274
275 private static Type stringValueOfOrStringBuilderAppendType(Type type) {
276 int sort = type.getSort();
277 return sort == Type.OBJECT || sort == Type.ARRAY
278 ? AsmTypeConstants.OBJECT_TYPE
279 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
280 }
281
282 public static void genThrow(MethodVisitor mv, String exception, String message) {
283 InstructionAdapter iv = new InstructionAdapter(mv);
284 iv.anew(Type.getObjectType(exception));
285 iv.dup();
286 iv.aconst(message);
287 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
288 iv.athrow();
289 }
290
291 public static void genMethodThrow(MethodVisitor mv, String exception, String message) {
292 mv.visitCode();
293 genThrow(mv, exception, message);
294 mv.visitMaxs(-1, -1);
295 mv.visitEnd();
296 }
297
298 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
299 ClassifierDescriptor captureThis = closure.getCaptureThis();
300 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
301 if (captureThis != null) {
302 v.newField(null, access, CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis).getDescriptor(), null,
303 null);
304 }
305
306 ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
307 if (captureReceiver != null) {
308 v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiver).getDescriptor(),
309 null, null);
310 }
311
312 List<Pair<String, Type>> fields = closure.getRecordedFields();
313 for (Pair<String, Type> field : fields) {
314 v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
315 }
316 }
317
318 public static void genInitSingletonField(Type classAsmType, InstructionAdapter iv) {
319 genInitSingletonField(classAsmType, JvmAbi.INSTANCE_FIELD, classAsmType, iv);
320 }
321
322 public static void genInitSingletonField(FieldInfo info, InstructionAdapter iv) {
323 assert info.isStatic();
324 genInitSingletonField(info.getOwnerType(), info.getFieldName(), info.getFieldType(), iv);
325 }
326
327 public static void genInitSingletonField(Type fieldOwnerType, String fieldName, Type fieldAsmType, InstructionAdapter iv) {
328 iv.anew(fieldAsmType);
329 iv.dup();
330 iv.invokespecial(fieldAsmType.getInternalName(), "<init>", "()V");
331 iv.putstatic(fieldOwnerType.getInternalName(), fieldName, fieldAsmType.getDescriptor());
332 }
333
334 public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
335 assert !info.isStatic();
336 Type fieldType = info.getFieldType();
337 iv.load(0, info.getOwnerType());//this
338 iv.load(index, fieldType); //param
339 iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
340 index += fieldType.getSize();
341 return index;
342 }
343
344 public static void genStringBuilderConstructor(InstructionAdapter v) {
345 v.visitTypeInsn(NEW, "java/lang/StringBuilder");
346 v.dup();
347 v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
348 }
349
350 public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
351 type = stringValueOfOrStringBuilderAppendType(type);
352 v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
353 }
354
355 public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
356 Type type = stringValueOfOrStringBuilderAppendType(receiverType);
357 receiver.put(type, v);
358 v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
359 return StackValue.onStack(JAVA_STRING_TYPE);
360 }
361
362 static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
363 if (type.getSort() == Type.ARRAY) {
364 Type elementType = correctElementType(type);
365 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
366 iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
367 }
368 else {
369 iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
370 }
371 }
372 else if (type.getSort() == Type.OBJECT) {
373 iv.invokevirtual("java/lang/Object", "hashCode", "()I");
374 }
375 else if (type.getSort() == Type.LONG) {
376 genLongHashCode(mv, iv);
377 }
378 else if (type.getSort() == Type.DOUBLE) {
379 iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
380 genLongHashCode(mv, iv);
381 }
382 else if (type.getSort() == Type.FLOAT) {
383 iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
384 }
385 else if (type.getSort() == Type.BOOLEAN) {
386 Label end = new Label();
387 iv.dup();
388 iv.ifeq(end);
389 iv.pop();
390 iv.iconst(1);
391 iv.mark(end);
392 }
393 else { // byte short char int
394 // do nothing
395 }
396 }
397
398 private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
399 iv.dup2();
400 iv.iconst(32);
401 iv.ushr(Type.LONG_TYPE);
402 iv.xor(Type.LONG_TYPE);
403 mv.visitInsn(L2I);
404 }
405
406 static void genInvertBoolean(InstructionAdapter v) {
407 v.iconst(1);
408 v.xor(Type.INT_TYPE);
409 }
410
411 public static StackValue genEqualsForExpressionsOnStack(
412 InstructionAdapter v,
413 IElementType opToken,
414 Type leftType,
415 Type rightType
416 ) {
417 if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
418 return StackValue.cmp(opToken, leftType);
419 }
420 else {
421 if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
422 return StackValue.cmp(opToken, leftType);
423 }
424 else {
425 v.invokestatic("jet/runtime/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
426
427 if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
428 genInvertBoolean(v);
429 }
430
431 return StackValue.onStack(Type.BOOLEAN_TYPE);
432 }
433 }
434 }
435
436 public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
437 if (expectedType == Type.LONG_TYPE) {
438 v.lconst(myDelta);
439 }
440 else if (expectedType == Type.FLOAT_TYPE) {
441 v.fconst(myDelta);
442 }
443 else if (expectedType == Type.DOUBLE_TYPE) {
444 v.dconst(myDelta);
445 }
446 else {
447 v.iconst(myDelta);
448 v.add(Type.INT_TYPE);
449 StackValue.coerce(Type.INT_TYPE, expectedType, v);
450 return;
451 }
452 v.add(expectedType);
453 }
454
455 public static Type genNegate(Type expectedType, InstructionAdapter v) {
456 if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
457 expectedType = Type.INT_TYPE;
458 }
459 v.neg(expectedType);
460 return expectedType;
461 }
462
463 public static void genStubCode(MethodVisitor mv) {
464 genMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
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().mapReturnType(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("jet/runtime/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(type);
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("jet/runtime/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 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
642 if (type.getSize() == 2) {
643 v.pop2();
644 }
645 else {
646 v.pop();
647 }
648 }
649
650 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
651 if (type.getSize() == 2) {
652 v.dup2();
653 }
654 else {
655 v.dup();
656 }
657 }
658
659 }