001 /*
002 * Copyright 2010-2016 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.kotlin.codegen;
018
019 import com.intellij.psi.tree.IElementType;
020 import kotlin.Unit;
021 import kotlin.collections.ArraysKt;
022 import kotlin.collections.CollectionsKt;
023 import kotlin.jvm.functions.Function1;
024 import org.jetbrains.annotations.Contract;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
028 import org.jetbrains.kotlin.builtins.PrimitiveType;
029 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
030 import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty;
031 import org.jetbrains.kotlin.codegen.state.GenerationState;
032 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
033 import org.jetbrains.kotlin.descriptors.*;
034 import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
035 import org.jetbrains.kotlin.load.java.JvmAbi;
036 import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
037 import org.jetbrains.kotlin.psi.KtExpression;
038 import org.jetbrains.kotlin.resolve.DescriptorUtils;
039 import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor;
040 import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
041 import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
042 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
043 import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
044 import org.jetbrains.kotlin.resolve.constants.ConstantValue;
045 import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
046 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
047 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
048 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
049 import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor;
050 import org.jetbrains.kotlin.types.KotlinType;
051 import org.jetbrains.org.objectweb.asm.Label;
052 import org.jetbrains.org.objectweb.asm.Type;
053 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
054
055 import java.util.List;
056
057 import static org.jetbrains.kotlin.codegen.AsmUtil.*;
058 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
059 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
060
061 public abstract class StackValue {
062
063 private static final String NULLABLE_BYTE_TYPE_NAME = "java/lang/Byte";
064 private static final String NULLABLE_SHORT_TYPE_NAME = "java/lang/Short";
065 private static final String NULLABLE_LONG_TYPE_NAME = "java/lang/Long";
066
067 public static final StackValue.Local LOCAL_0 = local(0, OBJECT_TYPE);
068 private static final StackValue UNIT = operation(UNIT_TYPE, new Function1<InstructionAdapter, Unit>() {
069 @Override
070 public Unit invoke(InstructionAdapter v) {
071 v.visitFieldInsn(GETSTATIC, UNIT_TYPE.getInternalName(), JvmAbi.INSTANCE_FIELD, UNIT_TYPE.getDescriptor());
072 return null;
073 }
074 });
075
076 @NotNull
077 public final Type type;
078 private final boolean canHaveSideEffects;
079
080 protected StackValue(@NotNull Type type) {
081 this(type, true);
082 }
083
084 protected StackValue(@NotNull Type type, boolean canHaveSideEffects) {
085 this.type = type;
086 this.canHaveSideEffects = canHaveSideEffects;
087 }
088
089 /**
090 * This method is called to put the value on the top of the JVM stack if <code>depth</code> other values have been put on the
091 * JVM stack after this value was generated.
092 *
093 * @param type the type as which the value should be put
094 * @param v the visitor used to genClassOrObject the instructions
095 * @param depth the number of new values put onto the stack
096 */
097 public void moveToTopOfStack(@NotNull Type type, @NotNull InstructionAdapter v, int depth) {
098 put(type, v);
099 }
100
101 public void put(@NotNull Type type, @NotNull InstructionAdapter v) {
102 put(type, v, false);
103 }
104
105 public void put(@NotNull Type type, @NotNull InstructionAdapter v, boolean skipReceiver) {
106 if (!skipReceiver) {
107 putReceiver(v, true);
108 }
109 putSelector(type, v);
110 }
111
112 public abstract void putSelector(@NotNull Type type, @NotNull InstructionAdapter v);
113
114 public boolean isNonStaticAccess(boolean isRead) {
115 return false;
116 }
117
118
119 public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) {
120 //by default there is no receiver
121 //if you have it inherit StackValueWithSimpleReceiver
122 }
123
124 public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
125 if (!Type.VOID_TYPE.equals(type)) {
126 AsmUtil.dup(v, type);
127 }
128 }
129
130 public void store(@NotNull StackValue value, @NotNull InstructionAdapter v) {
131 store(value, v, false);
132 }
133
134 public boolean canHaveSideEffects() {
135 return canHaveSideEffects;
136 }
137
138 public void store(@NotNull StackValue value, @NotNull InstructionAdapter v, boolean skipReceiver) {
139 if (!skipReceiver) {
140 putReceiver(v, false);
141 }
142 value.put(value.type, v);
143 storeSelector(value.type, v);
144 }
145
146 protected void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
147 throw new UnsupportedOperationException("Cannot store to value " + this);
148 }
149
150 @NotNull
151 public static Local local(int index, @NotNull Type type) {
152 return new Local(index, type);
153 }
154
155 @NotNull
156 public static StackValue shared(int index, @NotNull Type type) {
157 return new Shared(index, type);
158 }
159
160 @NotNull
161 public static StackValue onStack(@NotNull Type type) {
162 return type == Type.VOID_TYPE ? none() : new OnStack(type);
163 }
164
165 @NotNull
166 public static StackValue constant(@Nullable Object value, @NotNull Type type) {
167 if (type == Type.BOOLEAN_TYPE) {
168 assert value instanceof Boolean : "Value for boolean constant should have boolean type: " + value;
169 return BranchedValue.Companion.booleanConstant((Boolean) value);
170 }
171 else {
172 return new Constant(value, type);
173 }
174 }
175
176 @NotNull
177 public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) {
178 return BranchedValue.Companion.cmp(opToken, type, left, right);
179 }
180
181 @NotNull
182 public static StackValue not(@NotNull StackValue stackValue) {
183 return BranchedValue.Companion.createInvertValue(stackValue);
184 }
185
186 public static StackValue or(@NotNull StackValue left, @NotNull StackValue right) {
187 return new Or(left, right);
188 }
189
190 public static StackValue and(@NotNull StackValue left, @NotNull StackValue right) {
191 return new And(left, right);
192 }
193
194 public static StackValue compareIntWithZero(@NotNull StackValue argument, int operation) {
195 return new BranchedValue(argument, null, Type.INT_TYPE, operation);
196 }
197
198 public static StackValue compareWithNull(@NotNull StackValue argument, int operation) {
199 return new BranchedValue(argument, null, AsmTypes.OBJECT_TYPE, operation);
200 }
201
202 @NotNull
203 public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) {
204 return new ArrayElement(type, array, index);
205 }
206
207 @NotNull
208 public static StackValue collectionElement(
209 CollectionElementReceiver collectionElementReceiver,
210 Type type,
211 ResolvedCall<FunctionDescriptor> getter,
212 ResolvedCall<FunctionDescriptor> setter,
213 ExpressionCodegen codegen
214 ) {
215 return new CollectionElement(collectionElementReceiver, type, getter, setter, codegen);
216 }
217
218 @NotNull
219 public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
220 return field(type, owner, name, isStatic, receiver, null);
221 }
222
223 @NotNull
224 public static Field field(
225 @NotNull Type type,
226 @NotNull Type owner,
227 @NotNull String name,
228 boolean isStatic,
229 @NotNull StackValue receiver,
230 @Nullable DeclarationDescriptor descriptor
231 ) {
232 return new Field(type, owner, name, isStatic, receiver, descriptor);
233 }
234
235 @NotNull
236 public static Field field(@NotNull StackValue.Field field, @NotNull StackValue newReceiver) {
237 return field(field.type, field.owner, field.name, field.isStaticPut, newReceiver, field.descriptor);
238 }
239
240 @NotNull
241 public static Field field(@NotNull FieldInfo info, @NotNull StackValue receiver) {
242 return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), info.isStatic(), receiver);
243 }
244
245 @NotNull
246 public static StackValue changeReceiverForFieldAndSharedVar(@NotNull StackValueWithSimpleReceiver stackValue, @Nullable StackValue newReceiver) {
247 //TODO static check
248 if (newReceiver != null) {
249 if (!stackValue.isStaticPut) {
250 if (stackValue instanceof Field) {
251 return field((Field) stackValue, newReceiver);
252 }
253 else if (stackValue instanceof FieldForSharedVar) {
254 return fieldForSharedVar((FieldForSharedVar) stackValue, newReceiver);
255 }
256 }
257 }
258 return stackValue;
259 }
260
261 @NotNull
262 public static Property property(
263 @NotNull PropertyDescriptor descriptor,
264 @Nullable Type backingFieldOwner,
265 @NotNull Type type,
266 boolean isStaticBackingField,
267 @Nullable String fieldName,
268 @Nullable CallableMethod getter,
269 @Nullable CallableMethod setter,
270 GenerationState state,
271 @NotNull StackValue receiver
272 ) {
273 return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, state, receiver);
274 }
275
276 @NotNull
277 public static StackValue expression(Type type, KtExpression expression, ExpressionCodegen generator) {
278 return new Expression(type, expression, generator);
279 }
280
281 private static void box(Type type, Type toType, InstructionAdapter v) {
282 if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
283 v.cast(type, Type.BYTE_TYPE);
284 v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
285 }
286 else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
287 v.cast(type, Type.SHORT_TYPE);
288 v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
289 }
290 else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
291 v.cast(type, Type.LONG_TYPE);
292 v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
293 }
294 else if (type == Type.INT_TYPE) {
295 v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
296 }
297 else if (type == Type.BOOLEAN_TYPE) {
298 v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
299 }
300 else if (type == Type.CHAR_TYPE) {
301 v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
302 }
303 else if (type == Type.FLOAT_TYPE) {
304 v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
305 }
306 else if (type == Type.DOUBLE_TYPE) {
307 v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
308 }
309 }
310
311 private static void unbox(Type type, InstructionAdapter v) {
312 if (type == Type.INT_TYPE) {
313 v.invokevirtual("java/lang/Number", "intValue", "()I", false);
314 }
315 else if (type == Type.BOOLEAN_TYPE) {
316 v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
317 }
318 else if (type == Type.CHAR_TYPE) {
319 v.invokevirtual("java/lang/Character", "charValue", "()C", false);
320 }
321 else if (type == Type.SHORT_TYPE) {
322 v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
323 }
324 else if (type == Type.LONG_TYPE) {
325 v.invokevirtual("java/lang/Number", "longValue", "()J", false);
326 }
327 else if (type == Type.BYTE_TYPE) {
328 v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
329 }
330 else if (type == Type.FLOAT_TYPE) {
331 v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
332 }
333 else if (type == Type.DOUBLE_TYPE) {
334 v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
335 }
336 }
337
338 protected void coerceTo(@NotNull Type toType, @NotNull InstructionAdapter v) {
339 coerce(this.type, toType, v);
340 }
341
342 protected void coerceFrom(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
343 coerce(topOfStackType, this.type, v);
344 }
345
346 public static void coerce(@NotNull Type fromType, @NotNull Type toType, @NotNull InstructionAdapter v) {
347 if (toType.equals(fromType)) return;
348
349 if (toType.getSort() == Type.VOID) {
350 pop(v, fromType);
351 }
352 else if (fromType.getSort() == Type.VOID) {
353 if (toType.equals(UNIT_TYPE) || toType.equals(OBJECT_TYPE)) {
354 putUnitInstance(v);
355 }
356 else if (toType.getSort() == Type.OBJECT || toType.getSort() == Type.ARRAY) {
357 v.aconst(null);
358 }
359 else {
360 pushDefaultPrimitiveValueOnStack(toType, v);
361 }
362 }
363 else if (toType.equals(UNIT_TYPE)) {
364 if (fromType.equals(getType(Object.class))) {
365 v.checkcast(UNIT_TYPE);
366 }
367 else if (!fromType.equals(getType(Void.class))) {
368 pop(v, fromType);
369 putUnitInstance(v);
370 }
371 }
372 else if (toType.getSort() == Type.ARRAY) {
373 if (fromType.getSort() == Type.ARRAY &&
374 fromType.getElementType().equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(K_CLASS_ARRAY_TYPE)) {
375 wrapJavaClassesIntoKClasses(v);
376 }
377 else {
378 v.checkcast(toType);
379 }
380 }
381 else if (toType.getSort() == Type.OBJECT) {
382 if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
383 if (!toType.equals(OBJECT_TYPE)) {
384 if (fromType.equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(AsmTypes.K_CLASS_TYPE)) {
385 wrapJavaClassIntoKClass(v);
386 }
387 else {
388 v.checkcast(toType);
389 }
390 }
391 }
392 else {
393 box(fromType, toType, v);
394 }
395 }
396 else if (fromType.getSort() == Type.OBJECT) {
397 Type unboxedType = unboxPrimitiveTypeOrNull(fromType);
398 if (unboxedType != null) {
399 unbox(unboxedType, v);
400 coerce(unboxedType, toType, v);
401 }
402 else {
403 if (toType.getSort() == Type.BOOLEAN || toType.getSort() == Type.CHAR) {
404 coerce(fromType, boxType(toType), v);
405 }
406 else {
407 coerce(fromType, getType(Number.class), v);
408 }
409 unbox(toType, v);
410 }
411 }
412 else {
413 v.cast(fromType, toType);
414 }
415 }
416
417 public static void putUnitInstance(@NotNull InstructionAdapter v) {
418 unit().put(UNIT_TYPE, v);
419 }
420
421 public static StackValue unit() {
422 return UNIT;
423 }
424
425 public static StackValue none() {
426 return None.INSTANCE;
427 }
428
429 public static Field receiverWithRefWrapper(
430 @NotNull Type localType,
431 @NotNull Type classType,
432 @NotNull String fieldName,
433 @NotNull StackValue receiver,
434 @Nullable DeclarationDescriptor descriptor
435 ) {
436 return field(sharedTypeForType(localType), classType, fieldName, false, receiver, descriptor);
437 }
438
439 public static FieldForSharedVar fieldForSharedVar(
440 @NotNull Type localType,
441 @NotNull Type classType,
442 @NotNull String fieldName,
443 @NotNull Field refWrapper
444 ) {
445 return new FieldForSharedVar(localType, classType, fieldName, refWrapper);
446 }
447
448 @NotNull
449 public static FieldForSharedVar fieldForSharedVar(@NotNull FieldForSharedVar field, @NotNull StackValue newReceiver) {
450 Field oldReceiver = (Field) field.receiver;
451 Field newSharedVarReceiver = field(oldReceiver, newReceiver);
452 return new FieldForSharedVar(field.type, field.owner, field.name, newSharedVarReceiver);
453 }
454
455 public static StackValue coercion(@NotNull StackValue value, @NotNull Type castType) {
456 if (value.type.equals(castType)) {
457 return value;
458 }
459 return new CoercionValue(value, castType);
460 }
461
462 @NotNull
463 public static StackValue thisOrOuter(
464 @NotNull ExpressionCodegen codegen,
465 @NotNull ClassDescriptor descriptor,
466 boolean isSuper,
467 boolean castReceiver
468 ) {
469 // Coerce 'this' for the case when it is smart cast.
470 // Do not coerce for other cases due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
471 boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || (castReceiver && !isSuper);
472 return new ThisOuter(codegen, descriptor, isSuper, coerceType);
473 }
474
475 public static StackValue postIncrement(int index, int increment) {
476 return new PostIncrement(index, increment);
477 }
478
479 public static StackValue preIncrementForLocalVar(int index, int increment) {
480 return new PreIncrementForLocalVar(index, increment);
481 }
482
483 public static StackValue preIncrement(
484 @NotNull Type type,
485 @NotNull StackValue stackValue,
486 int delta,
487 ResolvedCall resolvedCall,
488 @NotNull ExpressionCodegen codegen
489 ) {
490 if (stackValue instanceof StackValue.Local && Type.INT_TYPE == stackValue.type) {
491 return preIncrementForLocalVar(((StackValue.Local) stackValue).index, delta);
492 }
493 return new PrefixIncrement(type, stackValue, resolvedCall, codegen);
494 }
495
496 public static StackValue receiver(
497 ResolvedCall<?> resolvedCall,
498 StackValue receiver,
499 ExpressionCodegen codegen,
500 @Nullable Callable callableMethod
501 ) {
502 ReceiverValue callDispatchReceiver = resolvedCall.getDispatchReceiver();
503 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
504 if (descriptor instanceof SyntheticFieldDescriptor) {
505 callDispatchReceiver = ((SyntheticFieldDescriptor) descriptor).getDispatchReceiverForBackend();
506 }
507
508 ReceiverValue callExtensionReceiver = resolvedCall.getExtensionReceiver();
509 if (callDispatchReceiver != null || callExtensionReceiver != null
510 || isLocalFunCall(callableMethod) || isCallToMemberObjectImportedByName(resolvedCall)) {
511 ReceiverParameterDescriptor dispatchReceiverParameter = descriptor.getDispatchReceiverParameter();
512 ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter();
513
514 if (descriptor.getOriginal() instanceof SamAdapterExtensionFunctionDescriptor) {
515 callDispatchReceiver = callExtensionReceiver;
516 callExtensionReceiver = null;
517 dispatchReceiverParameter = extensionReceiverParameter;
518 extensionReceiverParameter = null;
519 }
520 else if (descriptor instanceof SyntheticFieldDescriptor) {
521 dispatchReceiverParameter = ((SyntheticFieldDescriptor) descriptor).getDispatchReceiverParameterForBackend();
522 }
523
524 boolean hasExtensionReceiver = callExtensionReceiver != null;
525 StackValue dispatchReceiver = platformStaticCallIfPresent(
526 genReceiver(hasExtensionReceiver ? none() : receiver, codegen, resolvedCall, callableMethod, callDispatchReceiver, false),
527 descriptor
528 );
529 StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true);
530 Type type = CallReceiver.calcType(resolvedCall, dispatchReceiverParameter, extensionReceiverParameter, codegen.typeMapper, callableMethod, codegen.getState());
531 assert type != null : "Could not map receiver type for " + resolvedCall;
532 return new CallReceiver(dispatchReceiver, extensionReceiver, type);
533 }
534 return receiver;
535 }
536
537 private static StackValue genReceiver(
538 @NotNull StackValue receiver,
539 @NotNull ExpressionCodegen codegen,
540 @NotNull ResolvedCall resolvedCall,
541 @Nullable Callable callableMethod,
542 @Nullable ReceiverValue receiverValue,
543 boolean isExtension
544 ) {
545 if (receiver == none()) {
546 if (receiverValue != null) {
547 return codegen.generateReceiverValue(receiverValue, false);
548 }
549 else if (isLocalFunCall(callableMethod) && !isExtension) {
550 StackValue value = codegen.findLocalOrCapturedValue(resolvedCall.getResultingDescriptor().getOriginal());
551 assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
552 return value;
553 }
554 else if (isCallToMemberObjectImportedByName(resolvedCall)) {
555 return singleton(((ImportedFromObjectCallableDescriptor) resolvedCall.getResultingDescriptor()).getContainingObject(), codegen.typeMapper);
556 }
557 }
558 else if (receiverValue != null) {
559 return receiver;
560 }
561 return none();
562 }
563
564 private static boolean isCallToMemberObjectImportedByName(@NotNull ResolvedCall resolvedCall) {
565 return resolvedCall.getResultingDescriptor() instanceof ImportedFromObjectCallableDescriptor;
566 }
567
568 private static StackValue platformStaticCallIfPresent(@NotNull StackValue resultReceiver, @NotNull CallableDescriptor descriptor) {
569 if (AnnotationUtilKt.isPlatformStaticInObjectOrClass(descriptor)) {
570 if (resultReceiver.canHaveSideEffects()) {
571 return coercion(resultReceiver, Type.VOID_TYPE);
572 }
573 else {
574 return none();
575 }
576 }
577 return resultReceiver;
578 }
579
580 @Contract("null -> false")
581 private static boolean isLocalFunCall(@Nullable Callable callableMethod) {
582 return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
583 }
584
585 public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
586 if (receiverWithParameter instanceof CallReceiver) {
587 CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
588 return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type);
589 }
590 return receiverWithParameter;
591 }
592
593 @NotNull
594 public static Field enumEntry(@NotNull ClassDescriptor descriptor, @NotNull KotlinTypeMapper typeMapper) {
595 DeclarationDescriptor enumClass = descriptor.getContainingDeclaration();
596 assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor;
597 Type type = typeMapper.mapType((ClassDescriptor) enumClass);
598 return field(type, type, descriptor.getName().asString(), true, none(), descriptor);
599 }
600
601 @NotNull
602 public static Field singleton(@NotNull ClassDescriptor classDescriptor, @NotNull KotlinTypeMapper typeMapper) {
603 return field(FieldInfo.createForSingleton(classDescriptor, typeMapper), none());
604 }
605
606 public static Field singletonViaInstance(ClassDescriptor classDescriptor, KotlinTypeMapper typeMapper) {
607 return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper), none());
608 }
609
610 public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
611 return new OperationStackValue(type, lambda);
612 }
613
614 public static StackValue functionCall(Type type, Function1<InstructionAdapter, Unit> lambda) {
615 return new FunctionCallStackValue(type, lambda);
616 }
617
618 public static boolean couldSkipReceiverOnStaticCall(StackValue value) {
619 return value instanceof Local || value instanceof Constant;
620 }
621
622 private static class None extends StackValue {
623 public static final None INSTANCE = new None();
624
625 private None() {
626 super(Type.VOID_TYPE, false);
627 }
628
629 @Override
630 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
631 coerceTo(type, v);
632 }
633 }
634
635 public static class Local extends StackValue {
636 public final int index;
637
638 private Local(int index, Type type) {
639 super(type, false);
640 this.index = index;
641
642 if (index < 0) {
643 throw new IllegalStateException("local variable index must be non-negative");
644 }
645 }
646
647 @Override
648 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
649 v.load(index, this.type);
650 coerceTo(type, v);
651 // TODO unbox
652 }
653
654 @Override
655 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
656 coerceFrom(topOfStackType, v);
657 v.store(index, this.type);
658 }
659 }
660
661 public static class OnStack extends StackValue {
662 public OnStack(Type type) {
663 super(type);
664 }
665
666 @Override
667 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
668 coerceTo(type, v);
669 }
670
671 @Override
672 public void moveToTopOfStack(@NotNull Type type, @NotNull InstructionAdapter v, int depth) {
673 if (depth == 0) {
674 put(type, v);
675 }
676 else if (depth == 1) {
677 int size = this.type.getSize();
678 if (size == 1) {
679 v.swap();
680 }
681 else if (size == 2) {
682 v.dupX2();
683 v.pop();
684 }
685 else {
686 throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
687 }
688
689 coerceTo(type, v);
690 }
691 else if (depth == 2) {
692 int size = this.type.getSize();
693 if (size == 1) {
694 v.dup2X1();
695 v.pop2();
696 }
697 else if (size == 2) {
698 v.dup2X2();
699 v.pop2();
700 }
701 else {
702 throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
703 }
704
705 coerceTo(type, v);
706 }
707 else {
708 throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
709 }
710 }
711 }
712
713 private static class Constant extends StackValue {
714 @Nullable
715 private final Object value;
716
717 public Constant(@Nullable Object value, Type type) {
718 super(type, false);
719 assert !Type.BOOLEAN_TYPE.equals(type) : "Boolean constants should be created via 'StackValue.constant'";
720 this.value = value;
721 }
722
723 @Override
724 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
725 if (value instanceof Integer || value instanceof Byte || value instanceof Short) {
726 v.iconst(((Number) value).intValue());
727 }
728 else if (value instanceof Character) {
729 v.iconst(((Character) value).charValue());
730 }
731 else if (value instanceof Long) {
732 v.lconst((Long) value);
733 }
734 else if (value instanceof Float) {
735 v.fconst((Float) value);
736 }
737 else if (value instanceof Double) {
738 v.dconst((Double) value);
739 }
740 else {
741 v.aconst(value);
742 }
743
744 coerceTo(type, v);
745 }
746 }
747
748 private static class ArrayElement extends StackValueWithSimpleReceiver {
749 private final Type type;
750
751 public ArrayElement(Type type, StackValue array, StackValue index) {
752 super(type, false, false, new Receiver(Type.LONG_TYPE, array, index), true);
753 this.type = type;
754 }
755
756 @Override
757 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
758 coerceFrom(topOfStackType, v);
759 v.astore(this.type);
760 }
761
762 @Override
763 public int receiverSize() {
764 return 2;
765 }
766
767 @Override
768 public void putSelector(
769 @NotNull Type type, @NotNull InstructionAdapter v
770 ) {
771 v.aload(this.type); // assumes array and index are on the stack
772 coerceTo(type, v);
773 }
774 }
775
776 public static class CollectionElementReceiver extends StackValue {
777 private final Callable callable;
778 private final boolean isGetter;
779 private final ExpressionCodegen codegen;
780 private final List<ResolvedValueArgument> valueArguments;
781 private final FrameMap frame;
782 private final StackValue receiver;
783 private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
784 private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
785 private DefaultCallArgs defaultArgs;
786 private CallGenerator callGenerator;
787 boolean isComplexOperationWithDup;
788
789 public CollectionElementReceiver(
790 @NotNull Callable callable,
791 @NotNull StackValue receiver,
792 ResolvedCall<FunctionDescriptor> resolvedGetCall,
793 ResolvedCall<FunctionDescriptor> resolvedSetCall,
794 boolean isGetter,
795 @NotNull ExpressionCodegen codegen,
796 List<ResolvedValueArgument> valueArguments
797 ) {
798 super(OBJECT_TYPE);
799 this.callable = callable;
800
801 this.isGetter = isGetter;
802 this.receiver = receiver;
803 this.resolvedGetCall = resolvedGetCall;
804 this.resolvedSetCall = resolvedSetCall;
805 this.valueArguments = valueArguments;
806 this.codegen = codegen;
807 this.frame = codegen.myFrameMap;
808 }
809
810 @Override
811 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
812 ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
813 StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
814 ArgumentGenerator generator = createArgumentGenerator();
815 newReceiver.put(newReceiver.type, v);
816 callGenerator.putHiddenParams();
817
818 defaultArgs = generator.generate(valueArguments, valueArguments);
819 }
820
821 private ArgumentGenerator createArgumentGenerator() {
822 assert callGenerator == null :
823 "'putSelector' and 'createArgumentGenerator' methods should be called once for CollectionElementReceiver: " + callable;
824 ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
825 assert resolvedCall != null : "Resolved call should be non-null: " + callable;
826 callGenerator =
827 !isComplexOperationWithDup ? codegen.getOrCreateCallGenerator(resolvedCall) : codegen.defaultCallGenerator;
828 return new CallBasedArgumentGenerator(
829 codegen,
830 callGenerator,
831 resolvedCall.getResultingDescriptor().getValueParameters(), callable.getValueParameterTypes()
832 );
833 }
834
835 @Override
836 public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
837 dupReceiver(v);
838 }
839
840 public void dupReceiver(@NotNull InstructionAdapter v) {
841 if (CollectionElement.isStandardStack(codegen.typeMapper, resolvedGetCall, 1) &&
842 CollectionElement.isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
843 v.dup2(); // collection and index
844 return;
845 }
846
847 FrameMap.Mark mark = frame.mark();
848
849 // indexes
850 List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
851 int firstParamIndex = -1;
852 for (int i = valueParameters.size() - 1; i >= 0; --i) {
853 Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType());
854 firstParamIndex = frame.enterTemp(type);
855 v.store(firstParamIndex, type);
856 }
857
858 ReceiverValue receiverParameter = resolvedGetCall.getExtensionReceiver();
859 int receiverIndex = -1;
860 if (receiverParameter != null) {
861 Type type = codegen.typeMapper.mapType(receiverParameter.getType());
862 receiverIndex = frame.enterTemp(type);
863 v.store(receiverIndex, type);
864 }
865
866 ReceiverValue dispatchReceiver = resolvedGetCall.getDispatchReceiver();
867 int thisIndex = -1;
868 if (dispatchReceiver != null) {
869 thisIndex = frame.enterTemp(OBJECT_TYPE);
870 v.store(thisIndex, OBJECT_TYPE);
871 }
872
873 // for setter
874
875 int realReceiverIndex;
876 Type realReceiverType;
877 if (receiverIndex != -1) {
878 realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
879 realReceiverIndex = receiverIndex;
880 }
881 else if (thisIndex != -1) {
882 realReceiverType = OBJECT_TYPE;
883 realReceiverIndex = thisIndex;
884 }
885 else {
886 throw new UnsupportedOperationException();
887 }
888
889 if (resolvedSetCall.getDispatchReceiver() != null) {
890 if (resolvedSetCall.getExtensionReceiver() != null) {
891 codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver(), false).put(OBJECT_TYPE, v);
892 }
893 v.load(realReceiverIndex, realReceiverType);
894 }
895 else {
896 if (resolvedSetCall.getExtensionReceiver() != null) {
897 v.load(realReceiverIndex, realReceiverType);
898 }
899 else {
900 throw new UnsupportedOperationException();
901 }
902 }
903
904 int index = firstParamIndex;
905 for (ValueParameterDescriptor valueParameter : valueParameters) {
906 Type type = codegen.typeMapper.mapType(valueParameter.getType());
907 v.load(index, type);
908 index -= type.getSize();
909 }
910
911 // restoring original
912 if (thisIndex != -1) {
913 v.load(thisIndex, OBJECT_TYPE);
914 }
915
916 if (receiverIndex != -1) {
917 v.load(receiverIndex, realReceiverType);
918 }
919
920 index = firstParamIndex;
921 for (ValueParameterDescriptor valueParameter : valueParameters) {
922 Type type = codegen.typeMapper.mapType(valueParameter.getType());
923 v.load(index, type);
924 index -= type.getSize();
925 }
926
927 mark.dropTo();
928 }
929 }
930
931 public static class CollectionElement extends StackValueWithSimpleReceiver {
932 private final Callable getter;
933 private final Callable setter;
934 private final ExpressionCodegen codegen;
935 private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
936 private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
937
938 public CollectionElement(
939 @NotNull CollectionElementReceiver collectionElementReceiver,
940 @NotNull Type type,
941 @Nullable ResolvedCall<FunctionDescriptor> resolvedGetCall,
942 @Nullable ResolvedCall<FunctionDescriptor> resolvedSetCall,
943 @NotNull ExpressionCodegen codegen
944 ) {
945 super(type, false, false, collectionElementReceiver, true);
946 this.resolvedGetCall = resolvedGetCall;
947 this.resolvedSetCall = resolvedSetCall;
948 this.setter = resolvedSetCall == null ? null :
949 codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(resolvedSetCall), false, resolvedSetCall);
950 this.getter = resolvedGetCall == null ? null :
951 codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(resolvedGetCall), false, resolvedGetCall);
952 this.codegen = codegen;
953 }
954
955 @Override
956 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
957 if (getter == null) {
958 throw new UnsupportedOperationException("no getter specified");
959 }
960 CallGenerator callGenerator = getCallGenerator();
961 callGenerator.genCall(getter, resolvedGetCall, genDefaultMaskIfPresent(callGenerator), codegen);
962 coerceTo(type, v);
963 }
964
965 private boolean genDefaultMaskIfPresent(CallGenerator callGenerator) {
966 DefaultCallArgs defaultArgs = ((CollectionElementReceiver) receiver).defaultArgs;
967 return defaultArgs.generateOnStackIfNeeded(callGenerator, true);
968 }
969
970 private CallGenerator getCallGenerator() {
971 CallGenerator generator = ((CollectionElementReceiver) receiver).callGenerator;
972 assert generator != null :
973 "CollectionElementReceiver should be putted on stack before CollectionElement:" +
974 " getCall = " + resolvedGetCall + ", setCall = " + resolvedSetCall;
975 return generator;
976 }
977
978 @Override
979 public int receiverSize() {
980 if (isStandardStack(codegen.typeMapper, resolvedGetCall, 1) && isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
981 return 2;
982 }
983 else {
984 return -1;
985 }
986 }
987
988 public static boolean isStandardStack(@NotNull KotlinTypeMapper typeMapper, @Nullable ResolvedCall<?> call, int valueParamsSize) {
989 if (call == null) {
990 return true;
991 }
992
993 List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
994 if (valueParameters.size() != valueParamsSize) {
995 return false;
996 }
997
998 for (ValueParameterDescriptor valueParameter : valueParameters) {
999 if (typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
1000 return false;
1001 }
1002 }
1003
1004 if (call.getDispatchReceiver() != null) {
1005 if (call.getExtensionReceiver() != null) {
1006 return false;
1007 }
1008 }
1009 else {
1010 //noinspection ConstantConditions
1011 if (typeMapper.mapType(call.getResultingDescriptor().getExtensionReceiverParameter().getType()).getSize() != 1) {
1012 return false;
1013 }
1014 }
1015
1016 return true;
1017 }
1018
1019 @Override
1020 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1021 if (setter == null) {
1022 throw new UnsupportedOperationException("no setter specified");
1023 }
1024
1025 Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
1026 coerce(topOfStackType, lastParameterType, v);
1027
1028 getCallGenerator().afterParameterPut(lastParameterType, StackValue.onStack(lastParameterType),
1029 CollectionsKt.getLastIndex(setter.getValueParameterTypes()));
1030
1031 //Convention setter couldn't have default parameters, just getter can have it at last positions
1032 //We should remove default parameters of getter from stack*/
1033 //Note that it works only for non-inline case
1034 CollectionElementReceiver collectionElementReceiver = (CollectionElementReceiver) receiver;
1035 if (collectionElementReceiver.isGetter) {
1036 List<ResolvedValueArgument> arguments = collectionElementReceiver.valueArguments;
1037 List<Type> types = getter.getValueParameterTypes();
1038 for (int i = arguments.size() - 1; i >= 0; i--) {
1039 ResolvedValueArgument argument = arguments.get(i);
1040 if (argument instanceof DefaultValueArgument) {
1041 Type defaultType = types.get(i);
1042 AsmUtil.swap(v, lastParameterType, defaultType);
1043 AsmUtil.pop(v, defaultType);
1044 }
1045 }
1046 }
1047
1048 getCallGenerator().genCall(setter, resolvedSetCall, false, codegen);
1049 Type returnType = setter.getReturnType();
1050 if (returnType != Type.VOID_TYPE) {
1051 pop(v, returnType);
1052 }
1053 }
1054 }
1055
1056
1057 public static class Field extends StackValueWithSimpleReceiver {
1058 public final Type owner;
1059 public final String name;
1060 public final DeclarationDescriptor descriptor;
1061
1062 public Field(
1063 @NotNull Type type,
1064 @NotNull Type owner,
1065 @NotNull String name,
1066 boolean isStatic,
1067 @NotNull StackValue receiver,
1068 @Nullable DeclarationDescriptor descriptor
1069 ) {
1070 super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
1071 this.owner = owner;
1072 this.name = name;
1073 this.descriptor = descriptor;
1074 }
1075
1076 @Override
1077 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1078 v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1079 coerceTo(type, v);
1080 }
1081
1082 @Override
1083 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1084 coerceFrom(topOfStackType, v);
1085 v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1086 }
1087 }
1088
1089 static class Property extends StackValueWithSimpleReceiver {
1090 private final CallableMethod getter;
1091 private final CallableMethod setter;
1092 private final Type backingFieldOwner;
1093
1094 private final PropertyDescriptor descriptor;
1095 private final GenerationState state;
1096
1097 private final String fieldName;
1098
1099 public Property(
1100 @NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
1101 @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
1102 @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
1103 @NotNull StackValue receiver
1104 ) {
1105 super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
1106 this.backingFieldOwner = backingFieldOwner;
1107 this.getter = getter;
1108 this.setter = setter;
1109 this.descriptor = descriptor;
1110 this.state = state;
1111 this.fieldName = fieldName;
1112 }
1113
1114 @Override
1115 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1116 if (getter == null) {
1117 assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
1118 assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
1119 if (inlineJavaConstantIfNeeded(type, v)) return;
1120
1121 v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
1122 backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1123 genNotNullAssertionForLateInitIfNeeded(v);
1124 coerceTo(type, v);
1125 }
1126 else {
1127 getter.genInvokeInstruction(v);
1128 coerce(getter.getReturnType(), type, v);
1129
1130 KotlinType returnType = descriptor.getReturnType();
1131 if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
1132 v.aconst(null);
1133 v.athrow();
1134 }
1135 }
1136 }
1137
1138 private boolean inlineJavaConstantIfNeeded(@NotNull Type type, @NotNull InstructionAdapter v) {
1139 if (!JvmCodegenUtil.isInlinedJavaConstProperty(descriptor)) return false;
1140
1141 assert AsmUtil.isPrimitive(this.type) || AsmTypes.JAVA_STRING_TYPE.equals(this.type) :
1142 "Java const property should have primitive or string type: " + descriptor;
1143 assert isStaticPut : "Java const property should be static" + descriptor;
1144
1145 JavaPropertyDescriptor javaPropertyDescriptor = (JavaPropertyDescriptor) descriptor;
1146 ConstantValue<?> constantValue = javaPropertyDescriptor.getCompileTimeInitializer();
1147 if (constantValue == null) return false;
1148
1149 Object value = constantValue.getValue();
1150 if (this.type == Type.FLOAT_TYPE && value instanceof Double) {
1151 value = ((Double) value).floatValue();
1152 }
1153
1154 StackValue.constant(value, this.type).putSelector(type, v);
1155
1156 return true;
1157 }
1158
1159 private void genNotNullAssertionForLateInitIfNeeded(@NotNull InstructionAdapter v) {
1160 if (!descriptor.isLateInit()) return;
1161
1162 v.dup();
1163 Label ok = new Label();
1164 v.ifnonnull(ok);
1165 v.visitLdcInsn(descriptor.getName().asString());
1166 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwUninitializedPropertyAccessException", "(Ljava/lang/String;)V", false);
1167 v.mark(ok);
1168 }
1169
1170 @Override
1171 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1172 if (setter == null) {
1173 coerceFrom(topOfStackType, v);
1174 assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
1175 assert backingFieldOwner != null : "Property should have either a setter or a backingFieldOwner: " + descriptor;
1176 v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1177 }
1178 else {
1179 coerce(topOfStackType, ArraysKt.last(setter.getParameterTypes()), v);
1180 setter.genInvokeInstruction(v);
1181
1182 Type returnType = setter.getReturnType();
1183 if (returnType != Type.VOID_TYPE) {
1184 pop(v, returnType);
1185 }
1186 }
1187 }
1188
1189 private static boolean isStatic(boolean isStaticBackingField, @Nullable CallableMethod callable) {
1190 if (isStaticBackingField && callable == null) {
1191 return true;
1192 }
1193
1194 if (callable != null && callable.isStaticCall()) {
1195 List<JvmMethodParameterSignature> parameters = callable.getValueParameters();
1196 for (JvmMethodParameterSignature parameter : parameters) {
1197 JvmMethodParameterKind kind = parameter.getKind();
1198 if (kind == JvmMethodParameterKind.VALUE) {
1199 break;
1200 }
1201 if (kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) {
1202 return false;
1203 }
1204 }
1205 return true;
1206 }
1207
1208 return false;
1209 }
1210 }
1211
1212 private static class Expression extends StackValue {
1213 private final KtExpression expression;
1214 private final ExpressionCodegen generator;
1215
1216 public Expression(Type type, KtExpression expression, ExpressionCodegen generator) {
1217 super(type);
1218 this.expression = expression;
1219 this.generator = generator;
1220 }
1221
1222 @Override
1223 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1224 generator.gen(expression, type);
1225 }
1226 }
1227
1228 public static class Shared extends StackValueWithSimpleReceiver {
1229 private final int index;
1230
1231 public Shared(int index, Type type) {
1232 super(type, false, false, local(index, OBJECT_TYPE), false);
1233 this.index = index;
1234 }
1235
1236 public int getIndex() {
1237 return index;
1238 }
1239
1240 @Override
1241 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1242 Type refType = refType(this.type);
1243 Type sharedType = sharedTypeForType(this.type);
1244 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1245 coerceFrom(refType, v);
1246 coerceTo(type, v);
1247 }
1248
1249 @Override
1250 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1251 coerceFrom(topOfStackType, v);
1252 Type refType = refType(this.type);
1253 Type sharedType = sharedTypeForType(this.type);
1254 v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1255 }
1256 }
1257
1258 @NotNull
1259 public static Type sharedTypeForType(@NotNull Type type) {
1260 switch (type.getSort()) {
1261 case Type.OBJECT:
1262 case Type.ARRAY:
1263 return OBJECT_REF_TYPE;
1264 default:
1265 PrimitiveType primitiveType = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(type);
1266 if (primitiveType == null) throw new UnsupportedOperationException();
1267
1268 String typeName = primitiveType.getTypeName().getIdentifier();
1269 return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
1270 }
1271 }
1272
1273 public static Type refType(Type type) {
1274 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
1275 return OBJECT_TYPE;
1276 }
1277
1278 return type;
1279 }
1280
1281 public static class FieldForSharedVar extends StackValueWithSimpleReceiver {
1282 final Type owner;
1283 final String name;
1284
1285 public FieldForSharedVar(Type type, Type owner, String name, StackValue.Field receiver) {
1286 super(type, false, false, receiver, receiver.canHaveSideEffects());
1287 this.owner = owner;
1288 this.name = name;
1289 }
1290
1291 @Override
1292 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1293 Type sharedType = sharedTypeForType(this.type);
1294 Type refType = refType(this.type);
1295 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1296 coerceFrom(refType, v);
1297 coerceTo(type, v);
1298 }
1299
1300 @Override
1301 public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1302 coerceFrom(topOfStackType, v);
1303 v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
1304 }
1305 }
1306
1307 private static class ThisOuter extends StackValue {
1308 private final ExpressionCodegen codegen;
1309 private final ClassDescriptor descriptor;
1310 private final boolean isSuper;
1311 private final boolean coerceType;
1312
1313 public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) {
1314 super(OBJECT_TYPE, false);
1315 this.codegen = codegen;
1316 this.descriptor = descriptor;
1317 this.isSuper = isSuper;
1318 this.coerceType = coerceType;
1319 }
1320
1321 @Override
1322 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1323 StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
1324 stackValue.put(coerceType ? type : stackValue.type, v);
1325 }
1326 }
1327
1328 private static class PostIncrement extends StackValue {
1329 private final int index;
1330 private final int increment;
1331
1332 public PostIncrement(int index, int increment) {
1333 super(Type.INT_TYPE);
1334 this.index = index;
1335 this.increment = increment;
1336 }
1337
1338 @Override
1339 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1340 if (!type.equals(Type.VOID_TYPE)) {
1341 v.load(index, Type.INT_TYPE);
1342 coerceTo(type, v);
1343 }
1344 v.iinc(index, increment);
1345 }
1346 }
1347
1348 private static class PreIncrementForLocalVar extends StackValue {
1349 private final int index;
1350 private final int increment;
1351
1352 public PreIncrementForLocalVar(int index, int increment) {
1353 super(Type.INT_TYPE);
1354 this.index = index;
1355 this.increment = increment;
1356 }
1357
1358 @Override
1359 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1360 v.iinc(index, increment);
1361 if (!type.equals(Type.VOID_TYPE)) {
1362 v.load(index, Type.INT_TYPE);
1363 coerceTo(type, v);
1364 }
1365 }
1366 }
1367
1368 private static class PrefixIncrement extends StackValue {
1369 private final ResolvedCall resolvedCall;
1370 private final ExpressionCodegen codegen;
1371 private StackValue value;
1372
1373 public PrefixIncrement(
1374 @NotNull Type type,
1375 @NotNull StackValue value,
1376 ResolvedCall resolvedCall,
1377 @NotNull ExpressionCodegen codegen
1378 ) {
1379 super(type);
1380 this.value = value;
1381 this.resolvedCall = resolvedCall;
1382 this.codegen = codegen;
1383 }
1384
1385 @Override
1386 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1387 value = StackValue.complexReceiver(value, true, false, true);
1388 value.put(this.type, v);
1389
1390 value.store(codegen.invokeFunction(resolvedCall, StackValue.onStack(this.type)), v, true);
1391
1392 value.put(this.type, v, true);
1393 coerceTo(type, v);
1394 }
1395 }
1396
1397 public static class CallReceiver extends StackValue {
1398 private final StackValue dispatchReceiver;
1399 private final StackValue extensionReceiver;
1400
1401 public CallReceiver(
1402 @NotNull StackValue dispatchReceiver,
1403 @NotNull StackValue extensionReceiver,
1404 @NotNull Type type
1405 ) {
1406 super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects());
1407 this.dispatchReceiver = dispatchReceiver;
1408 this.extensionReceiver = extensionReceiver;
1409 }
1410
1411 @Nullable
1412 public static Type calcType(
1413 @NotNull ResolvedCall<?> resolvedCall,
1414 @Nullable ReceiverParameterDescriptor dispatchReceiver,
1415 @Nullable ReceiverParameterDescriptor extensionReceiver,
1416 @NotNull KotlinTypeMapper typeMapper,
1417 @Nullable Callable callableMethod,
1418 @NotNull GenerationState state
1419 ) {
1420 if (extensionReceiver != null) {
1421 CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
1422
1423 if (descriptor instanceof PropertyDescriptor &&
1424 // hackaround: boxing changes behaviour of T.javaClass intrinsic
1425 state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) != JavaClassProperty.INSTANCE
1426 ) {
1427 ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter();
1428 assert receiverCandidate != null;
1429 return typeMapper.mapType(receiverCandidate.getType());
1430 }
1431
1432 return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType());
1433 }
1434 else if (dispatchReceiver != null) {
1435 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1436
1437 if (AnnotationUtilKt.isPlatformStaticInObjectOrClass(descriptor)) {
1438 return Type.VOID_TYPE;
1439 }
1440
1441 if (callableMethod != null) {
1442 return callableMethod.getDispatchReceiverType();
1443 }
1444
1445 // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have
1446 // all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver.
1447 DeclarationDescriptor container = descriptor.getContainingDeclaration();
1448 if (container instanceof ClassDescriptor) {
1449 return typeMapper.mapClass((ClassDescriptor) container);
1450 }
1451
1452 return typeMapper.mapType(dispatchReceiver);
1453 }
1454 else if (isLocalFunCall(callableMethod)) {
1455 return callableMethod.getGenerateCalleeType();
1456 }
1457
1458 return Type.VOID_TYPE;
1459 }
1460
1461 @Override
1462 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1463 StackValue currentExtensionReceiver = extensionReceiver;
1464 boolean hasExtensionReceiver = extensionReceiver != none();
1465 if (extensionReceiver instanceof StackValue.SafeCall) {
1466 currentExtensionReceiver.put(currentExtensionReceiver.type, v);
1467 currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type);
1468 }
1469
1470 dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v);
1471
1472 currentExtensionReceiver
1473 .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize());
1474 }
1475
1476 @Override
1477 public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
1478 AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type);
1479 }
1480 }
1481
1482 public abstract static class StackValueWithSimpleReceiver extends StackValue {
1483
1484 public final boolean isStaticPut;
1485
1486 public final boolean isStaticStore;
1487 @NotNull
1488 public final StackValue receiver;
1489
1490 public StackValueWithSimpleReceiver(
1491 @NotNull Type type,
1492 boolean isStaticPut,
1493 boolean isStaticStore,
1494 @NotNull StackValue receiver,
1495 boolean canHaveSideEffects
1496 ) {
1497 super(type, canHaveSideEffects);
1498 this.receiver = receiver;
1499 this.isStaticPut = isStaticPut;
1500 this.isStaticStore = isStaticStore;
1501 }
1502
1503 @Override
1504 public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) {
1505 boolean hasReceiver = isNonStaticAccess(isRead);
1506 if (hasReceiver || receiver.canHaveSideEffects()) {
1507 receiver.put(hasReceiver ? receiver.type : Type.VOID_TYPE, v);
1508 }
1509 }
1510
1511 @Override
1512 public boolean isNonStaticAccess(boolean isRead) {
1513 return isRead ? !isStaticPut : !isStaticStore;
1514 }
1515
1516 public int receiverSize() {
1517 return receiver.type.getSize();
1518 }
1519
1520 @Override
1521 public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1522 if (!withWriteReceiver) {
1523 super.dup(v, false);
1524 }
1525 else {
1526 int receiverSize = isNonStaticAccess(false) ? receiverSize() : 0;
1527 switch (receiverSize) {
1528 case 0:
1529 AsmUtil.dup(v, type);
1530 break;
1531
1532 case 1:
1533 if (type.getSize() == 2) {
1534 v.dup2X1();
1535 }
1536 else {
1537 v.dupX1();
1538 }
1539 break;
1540
1541 case 2:
1542 if (type.getSize() == 2) {
1543 v.dup2X2();
1544 }
1545 else {
1546 v.dupX2();
1547 }
1548 break;
1549
1550 case -1:
1551 throw new UnsupportedOperationException();
1552 }
1553 }
1554 }
1555
1556 @Override
1557 public void store(
1558 @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1559 ) {
1560 if (!skipReceiver) {
1561 putReceiver(v, false);
1562 }
1563 rightSide.put(rightSide.type, v);
1564 storeSelector(rightSide.type, v);
1565 }
1566 }
1567
1568 private static class ComplexReceiver extends StackValue {
1569
1570 private final StackValueWithSimpleReceiver originalValueWithReceiver;
1571 private final boolean[] isReadOperations;
1572
1573 public ComplexReceiver(StackValueWithSimpleReceiver value, boolean[] isReadOperations) {
1574 super(value.type, value.receiver.canHaveSideEffects());
1575 this.originalValueWithReceiver = value;
1576 this.isReadOperations = isReadOperations;
1577 if (value instanceof CollectionElement) {
1578 if (value.receiver instanceof CollectionElementReceiver) {
1579 ((CollectionElementReceiver) value.receiver).isComplexOperationWithDup = true;
1580 }
1581 }
1582 }
1583
1584 @Override
1585 public void putSelector(
1586 @NotNull Type type, @NotNull InstructionAdapter v
1587 ) {
1588 boolean wasPut = false;
1589 StackValue receiver = originalValueWithReceiver.receiver;
1590 for (boolean operation : isReadOperations) {
1591 if (originalValueWithReceiver.isNonStaticAccess(operation)) {
1592 if (!wasPut) {
1593 receiver.put(receiver.type, v);
1594 wasPut = true;
1595 }
1596 else {
1597 receiver.dup(v, false);
1598 }
1599 }
1600 }
1601
1602 if (!wasPut && receiver.canHaveSideEffects()) {
1603 receiver.put(Type.VOID_TYPE, v);
1604 }
1605 }
1606 }
1607
1608 public static class Receiver extends StackValue {
1609
1610 private final StackValue[] instructions;
1611
1612 protected Receiver(@NotNull Type type, StackValue... receiverInstructions) {
1613 super(type);
1614 instructions = receiverInstructions;
1615 }
1616
1617 @Override
1618 public void putSelector(
1619 @NotNull Type type, @NotNull InstructionAdapter v
1620 ) {
1621 for (StackValue instruction : instructions) {
1622 instruction.put(instruction.type, v);
1623 }
1624 }
1625 }
1626
1627 public static class DelegatedForComplexReceiver extends StackValueWithSimpleReceiver {
1628
1629 public final StackValueWithSimpleReceiver originalValue;
1630
1631 public DelegatedForComplexReceiver(
1632 @NotNull Type type,
1633 @NotNull StackValueWithSimpleReceiver originalValue,
1634 @NotNull ComplexReceiver receiver
1635 ) {
1636 super(type, bothReceiverStatic(originalValue), bothReceiverStatic(originalValue), receiver, originalValue.canHaveSideEffects());
1637 this.originalValue = originalValue;
1638 }
1639
1640 private static boolean bothReceiverStatic(StackValueWithSimpleReceiver originalValue) {
1641 return !(originalValue.isNonStaticAccess(true) || originalValue.isNonStaticAccess(false));
1642 }
1643
1644 @Override
1645 public void putSelector(
1646 @NotNull Type type, @NotNull InstructionAdapter v
1647 ) {
1648 originalValue.putSelector(type, v);
1649 }
1650
1651 @Override
1652 public void storeSelector(
1653 @NotNull Type topOfStackType, @NotNull InstructionAdapter v
1654 ) {
1655 originalValue.storeSelector(topOfStackType, v);
1656 }
1657
1658 @Override
1659 public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1660 originalValue.dup(v, withWriteReceiver);
1661 }
1662 }
1663
1664 public static StackValue complexWriteReadReceiver(StackValue stackValue) {
1665 return complexReceiver(stackValue, false, true);
1666 }
1667
1668 private static StackValue complexReceiver(StackValue stackValue, boolean... isReadOperations) {
1669 if (stackValue instanceof StackValueWithSimpleReceiver) {
1670 return new DelegatedForComplexReceiver(stackValue.type, (StackValueWithSimpleReceiver) stackValue,
1671 new ComplexReceiver((StackValueWithSimpleReceiver) stackValue, isReadOperations));
1672 }
1673 else {
1674 return stackValue;
1675 }
1676 }
1677
1678 static class SafeCall extends StackValue {
1679
1680 @NotNull private final Type type;
1681 private final StackValue receiver;
1682 @Nullable private final Label ifNull;
1683
1684 public SafeCall(@NotNull Type type, @NotNull StackValue value, @Nullable Label ifNull) {
1685 super(type);
1686 this.type = type;
1687 this.receiver = value;
1688 this.ifNull = ifNull;
1689 }
1690
1691 @Override
1692 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1693 receiver.put(this.type, v);
1694 if (ifNull != null) {
1695 //not a primitive
1696 v.dup();
1697 v.ifnull(ifNull);
1698 }
1699 coerceTo(type, v);
1700 }
1701 }
1702
1703 static class SafeFallback extends StackValueWithSimpleReceiver {
1704
1705 @Nullable private final Label ifNull;
1706
1707 public SafeFallback(@NotNull Type type, @Nullable Label ifNull, StackValue receiver) {
1708 super(type, false, false, receiver, true);
1709 this.ifNull = ifNull;
1710 }
1711
1712 @Override
1713 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1714 Label end = new Label();
1715
1716 v.goTo(end);
1717 v.mark(ifNull);
1718 v.pop();
1719 if (!this.type.equals(Type.VOID_TYPE)) {
1720 v.aconst(null);
1721 }
1722 v.mark(end);
1723
1724 coerceTo(type, v);
1725 }
1726
1727 @Override
1728 public void store(
1729 @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1730 ) {
1731 receiver.store(rightSide, v, skipReceiver);
1732
1733 Label end = new Label();
1734 v.goTo(end);
1735 v.mark(ifNull);
1736 v.pop();
1737 v.mark(end);
1738 }
1739 }
1740 }
1741