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