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