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