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