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