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.BindingContext;
034 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.jet.lang.resolve.java.*;
037 import org.jetbrains.jet.lang.types.JetType;
038 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039 import org.jetbrains.jet.lexer.JetTokens;
040
041 import java.util.List;
042 import java.util.Map;
043 import java.util.Set;
044
045 import static org.jetbrains.asm4.Opcodes.*;
046 import static org.jetbrains.jet.codegen.CodegenUtil.*;
047 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
048 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
049
050 public class AsmUtil {
051 private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet(
052 KotlinBuiltIns.getInstance().getByte(),
053 KotlinBuiltIns.getInstance().getShort(),
054 KotlinBuiltIns.getInstance().getInt(),
055 KotlinBuiltIns.getInstance().getLong(),
056 KotlinBuiltIns.getInstance().getFloat(),
057 KotlinBuiltIns.getInstance().getDouble(),
058 KotlinBuiltIns.getInstance().getChar()
059 );
060
061 private static final int NO_FLAG_LOCAL = 0;
062 public static final int NO_FLAG_PACKAGE_PRIVATE = 0;
063
064 @NotNull
065 private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
066 .put(Visibilities.PRIVATE, ACC_PRIVATE)
067 .put(Visibilities.PROTECTED, ACC_PROTECTED)
068 .put(JavaDescriptorResolver.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED)
069 .put(JavaDescriptorResolver.PROTECTED_AND_PACKAGE, ACC_PROTECTED)
070 .put(Visibilities.PUBLIC, ACC_PUBLIC)
071 .put(Visibilities.INTERNAL, ACC_PUBLIC)
072 .put(Visibilities.LOCAL, NO_FLAG_LOCAL)
073 .put(JavaDescriptorResolver.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE)
074 .build();
075
076 public static final String CAPTURED_RECEIVER_FIELD = "receiver$0";
077 public static final String CAPTURED_THIS_FIELD = "this$0";
078
079 private static final String STUB_EXCEPTION = "java/lang/RuntimeException";
080 private static final String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath";
081
082 private AsmUtil() {
083 }
084
085 public static Type boxType(Type asmType) {
086 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByAsmType(asmType);
087 if (jvmPrimitiveType != null) {
088 return jvmPrimitiveType.getWrapper().getAsmType();
089 }
090 else {
091 return asmType;
092 }
093 }
094
095 public static boolean isIntPrimitive(Type type) {
096 return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
097 }
098
099 public static boolean isNumberPrimitive(Type type) {
100 return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
101 }
102
103 public static boolean isPrimitive(Type type) {
104 return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
105 }
106
107 public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
108 if (!(descriptor instanceof ClassDescriptor)) {
109 return false;
110 }
111 return PRIMITIVE_NUMBER_CLASSES.contains(descriptor);
112 }
113
114 public static Type correctElementType(Type type) {
115 String internalName = type.getInternalName();
116 assert internalName.charAt(0) == '[';
117 return Type.getType(internalName.substring(1));
118 }
119
120 public static Type unboxType(Type type) {
121 JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByWrapperAsmType(type);
122 if (jvmPrimitiveType != null) {
123 return jvmPrimitiveType.getAsmType();
124 }
125 else {
126 throw new UnsupportedOperationException("Unboxing: " + type);
127 }
128 }
129
130 public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
131 return (functionDescriptor.getModality() == Modality.ABSTRACT
132 || isInterface(functionDescriptor.getContainingDeclaration()))
133 && !isStaticMethod(kind, functionDescriptor);
134 }
135
136 public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) {
137 return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor);
138 }
139
140 public static boolean isStatic(OwnerKind kind) {
141 return kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.TRAIT_IMPL;
142 }
143
144 public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
145 int flags = getCommonCallableFlags(functionDescriptor);
146
147 if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
148 DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
149 if (!(containingDeclaration instanceof ClassDescriptor) ||
150 ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) {
151 flags |= ACC_FINAL;
152 }
153 }
154
155 if (isStaticMethod(kind, functionDescriptor)) {
156 flags |= ACC_STATIC;
157 }
158
159 if (isAbstractMethod(functionDescriptor, kind)) {
160 flags |= ACC_ABSTRACT;
161 }
162
163 if (JetTypeMapper.isAccessor(functionDescriptor)) {
164 flags |= ACC_SYNTHETIC;
165 }
166
167 return flags;
168 }
169
170 private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
171 int flags = getVisibilityAccessFlag(functionDescriptor);
172 flags |= getVarargsFlag(functionDescriptor);
173 flags |= getDeprecatedAccessFlag(functionDescriptor);
174 return flags;
175 }
176
177 //TODO: move mapping logic to front-end java
178 public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
179 Integer specialCase = specialCaseVisibility(descriptor);
180 if (specialCase != null) {
181 return specialCase;
182 }
183 Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility());
184 if (defaultMapping == null) {
185 throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend.");
186 }
187 return defaultMapping;
188 }
189
190 /*
191 Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
192 For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
193 Classes in byte code should be public or package private
194 */
195 public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) {
196 if (DescriptorUtils.isTopLevelDeclaration(descriptor) ||
197 descriptor.getVisibility() == Visibilities.PUBLIC ||
198 descriptor.getVisibility() == Visibilities.INTERNAL) {
199 return ACC_PUBLIC;
200 }
201 return NO_FLAG_PACKAGE_PRIVATE;
202 }
203
204 public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
205 if (descriptor instanceof PropertyAccessorDescriptor) {
206 return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
207 ? ACC_DEPRECATED
208 : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
209 }
210 else if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
211 return ACC_DEPRECATED;
212 }
213 return 0;
214 }
215
216 private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
217 if (!functionDescriptor.getValueParameters().isEmpty()
218 && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
219 .getVarargElementType() != null) {
220 return ACC_VARARGS;
221 }
222 return 0;
223 }
224
225 @Nullable
226 private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
227 DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
228 if (isInterface(containingDeclaration)) {
229 return ACC_PUBLIC;
230 }
231 Visibility memberVisibility = memberDescriptor.getVisibility();
232 if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
233 return ACC_PUBLIC;
234 }
235 if (memberVisibility != Visibilities.PRIVATE) {
236 return null;
237 }
238 // the following code is only for PRIVATE visibility of member
239 if (isEnumEntry(memberDescriptor)) {
240 return NO_FLAG_PACKAGE_PRIVATE;
241 }
242 if (memberDescriptor instanceof ConstructorDescriptor) {
243 ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
244 if (kind == ClassKind.OBJECT) {
245 return NO_FLAG_PACKAGE_PRIVATE;
246 }
247 else if (kind == ClassKind.ENUM_ENTRY) {
248 return NO_FLAG_PACKAGE_PRIVATE;
249 }
250 else if (kind == ClassKind.ENUM_CLASS) {
251 //TODO: should be ACC_PRIVATE
252 // see http://youtrack.jetbrains.com/issue/KT-2680
253 return ACC_PROTECTED;
254 }
255 }
256 if (containingDeclaration instanceof NamespaceDescriptor) {
257 return ACC_PUBLIC;
258 }
259 return null;
260 }
261
262 @NotNull
263 public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) {
264 JetType jetType = getSuperClass(traitDescriptor);
265 Type type = typeMapper.mapType(jetType);
266 if (type.getInternalName().equals("java/lang/Object")) {
267 return typeMapper.mapType(traitDescriptor.getDefaultType());
268 }
269 return type;
270 }
271
272 private static Type stringValueOfOrStringBuilderAppendType(Type type) {
273 int sort = type.getSort();
274 return sort == Type.OBJECT || sort == Type.ARRAY
275 ? AsmTypeConstants.OBJECT_TYPE
276 : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
277 }
278
279 public static void genThrow(MethodVisitor mv, String exception, String message) {
280 InstructionAdapter iv = new InstructionAdapter(mv);
281 iv.anew(Type.getObjectType(exception));
282 iv.dup();
283 iv.aconst(message);
284 iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
285 iv.athrow();
286 }
287
288 public static void genMethodThrow(MethodVisitor mv, String exception, String message) {
289 mv.visitCode();
290 genThrow(mv, exception, message);
291 mv.visitMaxs(-1, -1);
292 mv.visitEnd();
293 }
294
295 public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
296 ClassifierDescriptor captureThis = closure.getCaptureThis();
297 int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
298 if (captureThis != null) {
299 v.newField(null, access, CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis).getDescriptor(), null,
300 null);
301 }
302
303 ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
304 if (captureReceiver != null) {
305 v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiver).getDescriptor(),
306 null, null);
307 }
308
309 List<Pair<String, Type>> fields = closure.getRecordedFields();
310 for (Pair<String, Type> field : fields) {
311 v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
312 }
313 }
314
315 public static void genInitSingletonField(Type classAsmType, InstructionAdapter iv) {
316 genInitSingletonField(classAsmType, JvmAbi.INSTANCE_FIELD, classAsmType, iv);
317 }
318
319 public static void genInitSingletonField(FieldInfo info, InstructionAdapter iv) {
320 assert info.isStatic();
321 genInitSingletonField(info.getOwnerType(), info.getFieldName(), info.getFieldType(), iv);
322 }
323
324 public static void genInitSingletonField(Type fieldOwnerType, String fieldName, Type fieldAsmType, InstructionAdapter iv) {
325 iv.anew(fieldAsmType);
326 iv.dup();
327 iv.invokespecial(fieldAsmType.getInternalName(), "<init>", "()V");
328 iv.putstatic(fieldOwnerType.getInternalName(), fieldName, fieldAsmType.getDescriptor());
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 genStubCode(MethodVisitor mv) {
461 genMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
462 }
463
464 public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
465 if (stackTop.getSize() == 1) {
466 if (afterTop.getSize() == 1) {
467 v.swap();
468 } else {
469 v.dupX2();
470 v.pop();
471 }
472 } else {
473 if (afterTop.getSize() == 1) {
474 v.dup2X1();
475 } else {
476 v.dup2X2();
477 }
478 v.pop2();
479 }
480 }
481
482 public static void genNotNullAssertionsForParameters(
483 @NotNull InstructionAdapter v,
484 @NotNull GenerationState state,
485 @NotNull FunctionDescriptor descriptor,
486 @NotNull FrameMap frameMap
487 ) {
488 if (!state.isGenerateNotNullParamAssertions()) return;
489
490 // Private method is not accessible from other classes, no assertions needed
491 if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
492
493 for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
494 JetType type = parameter.getReturnType();
495 if (type == null || isNullableType(type)) continue;
496
497 int index = frameMap.getIndex(parameter);
498 Type asmType = state.getTypeMapper().mapReturnType(type);
499 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
500 v.load(index, asmType);
501 v.visitLdcInsn(parameter.getName().asString());
502 v.invokestatic("jet/runtime/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V");
503 }
504 }
505 }
506
507 public static void genNotNullAssertionForField(
508 @NotNull InstructionAdapter v,
509 @NotNull GenerationState state,
510 @NotNull PropertyDescriptor descriptor
511 ) {
512 genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
513 }
514
515 public static void genNotNullAssertionForMethod(
516 @NotNull InstructionAdapter v,
517 @NotNull GenerationState state,
518 @NotNull ResolvedCall resolvedCall
519 ) {
520 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
521 if (descriptor instanceof ConstructorDescriptor) return;
522
523 genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
524 }
525
526 private static void genNotNullAssertion(
527 @NotNull InstructionAdapter v,
528 @NotNull GenerationState state,
529 @NotNull CallableDescriptor descriptor,
530 @NotNull String assertMethodToCall
531 ) {
532 if (!state.isGenerateNotNullAssertions()) return;
533
534 if (!isDeclaredInJava(descriptor, state.getBindingContext())) return;
535
536 JetType type = descriptor.getReturnType();
537 if (type == null || isNullableType(type)) return;
538
539 Type asmType = state.getTypeMapper().mapReturnType(type);
540 if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
541 v.dup();
542 v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
543 v.visitLdcInsn(descriptor.getName().asString());
544 v.invokestatic("jet/runtime/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V");
545 }
546 }
547
548 private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor, @NotNull BindingContext context) {
549 CallableDescriptor descriptor = callableDescriptor;
550 while (true) {
551 if (Boolean.TRUE.equals(context.get(JavaBindingContext.IS_DECLARED_IN_JAVA, descriptor))) {
552 return true;
553 }
554 CallableDescriptor original = descriptor.getOriginal();
555 if (descriptor == original) break;
556 descriptor = original;
557 }
558 return false;
559 }
560
561 public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
562 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
563 v.aconst(null);
564 }
565 else {
566 pushDefaultPrimitiveValueOnStack(type, v);
567 }
568 }
569
570 public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
571 if (type.getSort() == Type.FLOAT) {
572 v.fconst(0);
573 }
574 else if (type.getSort() == Type.DOUBLE) {
575 v.dconst(0);
576 }
577 else if (type.getSort() == Type.LONG) {
578 v.lconst(0);
579 }
580 else {
581 v.iconst(0);
582 }
583 }
584
585 public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
586 return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS);
587 }
588
589 public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
590 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
591 if (isDelegate || isExtensionProperty) {
592 return ACC_PRIVATE;
593 } else {
594 return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE;
595 }
596 }
597
598 private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
599 if (!propertyDescriptor.isVar() ) {
600 return propertyDescriptor;
601 } else {
602 return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
603 }
604 }
605
606 public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
607 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
608 return !propertyDescriptor.isVar() && !isExtensionProperty
609 && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
610 && areBothAccessorDefault(propertyDescriptor)
611 && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
612 }
613
614 public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
615 return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS);
616 }
617
618 private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
619 return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
620 && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
621 }
622
623 private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
624 return accessorDescriptor == null || !accessorDescriptor.hasBody();
625 }
626
627 private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) {
628 return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
629 }
630
631 public static Type comparisonOperandType(Type left, Type right) {
632 if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
633 if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
634 if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
635 return Type.INT_TYPE;
636 }
637
638 public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
639 if (type.getSize() == 2) {
640 v.pop2();
641 }
642 else {
643 v.pop();
644 }
645 }
646
647 public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
648 if (type.getSize() == 2) {
649 v.dup2();
650 }
651 else {
652 v.dup();
653 }
654 }
655
656 }