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