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