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