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.google.common.collect.Lists; 020 import com.google.common.collect.Maps; 021 import com.intellij.openapi.progress.ProcessCanceledException; 022 import com.intellij.openapi.util.Ref; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.tree.IElementType; 025 import com.intellij.util.ArrayUtil; 026 import com.intellij.util.Function; 027 import com.intellij.util.containers.Stack; 028 import kotlin.Pair; 029 import kotlin.Unit; 030 import kotlin.collections.CollectionsKt; 031 import kotlin.jvm.functions.Function1; 032 import org.jetbrains.annotations.NotNull; 033 import org.jetbrains.annotations.Nullable; 034 import org.jetbrains.kotlin.backend.common.CodegenUtil; 035 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 036 import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; 037 import org.jetbrains.kotlin.codegen.binding.CodegenBinding; 038 import org.jetbrains.kotlin.codegen.context.*; 039 import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; 040 import org.jetbrains.kotlin.codegen.inline.*; 041 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicCallable; 042 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; 043 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; 044 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicPropertyGetter; 045 import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt; 046 import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; 047 import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; 048 import org.jetbrains.kotlin.codegen.state.GenerationState; 049 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; 050 import org.jetbrains.kotlin.codegen.when.SwitchCodegen; 051 import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; 052 import org.jetbrains.kotlin.descriptors.*; 053 import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; 054 import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; 055 import org.jetbrains.kotlin.diagnostics.Errors; 056 import org.jetbrains.kotlin.incremental.components.NoLookupLocation; 057 import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo; 058 import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesKt; 059 import org.jetbrains.kotlin.lexer.KtTokens; 060 import org.jetbrains.kotlin.load.java.JvmAbi; 061 import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor; 062 import org.jetbrains.kotlin.name.Name; 063 import org.jetbrains.kotlin.psi.*; 064 import org.jetbrains.kotlin.resolve.BindingContext; 065 import org.jetbrains.kotlin.resolve.BindingContextUtils; 066 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 067 import org.jetbrains.kotlin.resolve.DescriptorUtils; 068 import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; 069 import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt; 070 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; 071 import org.jetbrains.kotlin.resolve.calls.model.*; 072 import org.jetbrains.kotlin.resolve.calls.util.CallMaker; 073 import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject; 074 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; 075 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 076 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; 077 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt; 078 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; 079 import org.jetbrains.kotlin.resolve.inline.InlineUtil; 080 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; 081 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 082 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 083 import org.jetbrains.kotlin.resolve.scopes.receivers.*; 084 import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor; 085 import org.jetbrains.kotlin.types.KotlinType; 086 import org.jetbrains.kotlin.types.TypeProjection; 087 import org.jetbrains.kotlin.types.TypeUtils; 088 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; 089 import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt; 090 import org.jetbrains.org.objectweb.asm.Label; 091 import org.jetbrains.org.objectweb.asm.MethodVisitor; 092 import org.jetbrains.org.objectweb.asm.Opcodes; 093 import org.jetbrains.org.objectweb.asm.Type; 094 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 095 import org.jetbrains.org.objectweb.asm.commons.Method; 096 097 import java.util.*; 098 099 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt; 100 import static org.jetbrains.kotlin.codegen.AsmUtil.*; 101 import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; 102 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; 103 import static org.jetbrains.kotlin.resolve.BindingContext.*; 104 import static org.jetbrains.kotlin.resolve.BindingContextUtils.*; 105 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 106 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject; 107 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; 108 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression; 109 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral; 110 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 111 112 public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> implements LocalLookup { 113 private final GenerationState state; 114 final KotlinTypeMapper typeMapper; 115 private final BindingContext bindingContext; 116 117 public final InstructionAdapter v; 118 public final FrameMap myFrameMap; 119 private final MethodContext context; 120 private final Type returnType; 121 122 private final CodegenStatementVisitor statementVisitor = new CodegenStatementVisitor(this); 123 private final MemberCodegen<?> parentCodegen; 124 private final TailRecursionCodegen tailRecursionCodegen; 125 public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this); 126 127 private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>(); 128 129 /* 130 * When we create a temporary variable to hold some value not to compute it many times 131 * we put it into this map to emit access to that variable instead of evaluating the whole expression 132 */ 133 public final Map<KtElement, StackValue> tempVariables = Maps.newHashMap(); 134 135 private int myLastLineNumber = -1; 136 private boolean shouldMarkLineNumbers = true; 137 private int finallyDepth = 0; 138 139 public ExpressionCodegen( 140 @NotNull MethodVisitor mv, 141 @NotNull FrameMap frameMap, 142 @NotNull Type returnType, 143 @NotNull MethodContext context, 144 @NotNull GenerationState state, 145 @NotNull MemberCodegen<?> parentCodegen 146 ) { 147 this.state = state; 148 this.typeMapper = state.getTypeMapper(); 149 this.bindingContext = state.getBindingContext(); 150 this.v = new InstructionAdapter(mv); 151 this.myFrameMap = frameMap; 152 this.context = context; 153 this.returnType = returnType; 154 this.parentCodegen = parentCodegen; 155 this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state); 156 } 157 158 static class BlockStackElement { 159 } 160 161 static class LoopBlockStackElement extends BlockStackElement { 162 final Label continueLabel; 163 final Label breakLabel; 164 public final KtSimpleNameExpression targetLabel; 165 166 LoopBlockStackElement(Label breakLabel, Label continueLabel, KtSimpleNameExpression targetLabel) { 167 this.breakLabel = breakLabel; 168 this.continueLabel = continueLabel; 169 this.targetLabel = targetLabel; 170 } 171 } 172 173 static class FinallyBlockStackElement extends BlockStackElement { 174 List<Label> gaps = new ArrayList<Label>(); 175 176 final KtTryExpression expression; 177 178 FinallyBlockStackElement(KtTryExpression expression) { 179 this.expression = expression; 180 } 181 182 private void addGapLabel(Label label){ 183 gaps.add(label); 184 } 185 } 186 187 @NotNull 188 public GenerationState getState() { 189 return state; 190 } 191 192 @NotNull 193 public BindingContext getBindingContext() { 194 return bindingContext; 195 } 196 197 @NotNull 198 public MemberCodegen<?> getParentCodegen() { 199 return parentCodegen; 200 } 201 202 @NotNull 203 public ObjectLiteralResult generateObjectLiteral(@NotNull KtObjectLiteralExpression literal) { 204 KtObjectDeclaration objectDeclaration = literal.getObjectDeclaration(); 205 206 ClassDescriptor classDescriptor = bindingContext.get(CLASS, objectDeclaration); 207 assert classDescriptor != null; 208 209 Type asmType = asmTypeForAnonymousClass(bindingContext, objectDeclaration); 210 ClassBuilder classBuilder = state.getFactory().newVisitor( 211 JvmDeclarationOriginKt.OtherOrigin(objectDeclaration, classDescriptor), 212 asmType, 213 literal.getContainingFile() 214 ); 215 216 ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION); 217 218 MemberCodegen literalCodegen = new ImplementationBodyCodegen( 219 objectDeclaration, objectContext, classBuilder, state, getParentCodegen(), 220 /* isLocal = */ true); 221 literalCodegen.generate(); 222 223 addReifiedParametersFromSignature(literalCodegen, classDescriptor); 224 propagateChildReifiedTypeParametersUsages(literalCodegen.getReifiedTypeParametersUsages()); 225 226 return new ObjectLiteralResult( 227 literalCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters(), 228 classDescriptor 229 ); 230 } 231 232 private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) { 233 for (KotlinType type : descriptor.getTypeConstructor().getSupertypes()) { 234 for (TypeProjection supertypeArgument : type.getArguments()) { 235 TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType()); 236 if (parameterDescriptor != null && parameterDescriptor.isReified()) { 237 member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString()); 238 } 239 } 240 } 241 } 242 243 private static class ObjectLiteralResult { 244 private final boolean wereReifiedMarkers; 245 private final ClassDescriptor classDescriptor; 246 247 public ObjectLiteralResult(boolean wereReifiedMarkers, @NotNull ClassDescriptor classDescriptor) { 248 this.wereReifiedMarkers = wereReifiedMarkers; 249 this.classDescriptor = classDescriptor; 250 } 251 } 252 253 @NotNull 254 private StackValue castToRequiredTypeOfInterfaceIfNeeded( 255 StackValue inner, 256 @NotNull ClassDescriptor provided, 257 @NotNull ClassDescriptor required 258 ) { 259 if (!isJvmInterface(provided) && isJvmInterface(required)) { 260 return StackValue.coercion(inner, asmType(required.getDefaultType())); 261 } 262 263 return inner; 264 } 265 266 public StackValue genQualified(StackValue receiver, KtElement selector) { 267 return genQualified(receiver, selector, this); 268 } 269 270 private StackValue genQualified(StackValue receiver, KtElement selector, KtVisitor<StackValue, StackValue> visitor) { 271 if (tempVariables.containsKey(selector)) { 272 throw new IllegalStateException("Inconsistent state: expression saved to a temporary variable is a selector"); 273 } 274 if (!(selector instanceof KtBlockExpression)) { 275 markStartLineNumber(selector); 276 } 277 try { 278 if (selector instanceof KtExpression) { 279 StackValue samValue = genSamInterfaceValue((KtExpression) selector, visitor); 280 if (samValue != null) { 281 return samValue; 282 } 283 } 284 285 StackValue stackValue = selector.accept(visitor, receiver); 286 287 RuntimeAssertionInfo runtimeAssertionInfo = null; 288 if (selector instanceof KtExpression) { 289 runtimeAssertionInfo = bindingContext.get(BindingContextSlicesKt.getRUNTIME_ASSERTION_INFO(), (KtExpression) selector); 290 } 291 292 if (BuiltinSpecialBridgesKt.isValueArgumentForCallToMethodWithTypeCheckBarrier(selector, bindingContext)) return stackValue; 293 294 return genNotNullAssertions(state, stackValue, runtimeAssertionInfo); 295 } 296 catch (ProcessCanceledException e) { 297 throw e; 298 } 299 catch (CompilationException e) { 300 throw e; 301 } 302 catch (Throwable error) { 303 String message = error.getMessage(); 304 throw new CompilationException(message != null ? message : "null", error, selector); 305 } 306 } 307 308 public StackValue gen(KtElement expr) { 309 StackValue tempVar = tempVariables.get(expr); 310 return tempVar != null ? tempVar : genQualified(StackValue.none(), expr); 311 } 312 313 public void gen(KtElement expr, Type type) { 314 StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr); 315 // for repl store the result of the last line into special field 316 if (value.type != Type.VOID_TYPE && state.getReplSpecific().getShouldGenerateScriptResultValue()) { 317 ScriptContext context = getScriptContext(); 318 if (expr == context.getLastStatement()) { 319 StackValue.Field resultValue = StackValue.field(context.getResultFieldInfo(), StackValue.LOCAL_0); 320 resultValue.store(value, v); 321 state.getReplSpecific().setHasResult(true); 322 return; 323 } 324 } 325 326 value.put(type, v); 327 } 328 329 @NotNull 330 private ScriptContext getScriptContext() { 331 CodegenContext context = getContext(); 332 while (!(context instanceof ScriptContext)) { 333 context = context.getParentContext(); 334 } 335 return (ScriptContext) context; 336 } 337 338 public StackValue genLazy(KtElement expr, Type type) { 339 StackValue value = gen(expr); 340 return StackValue.coercion(value, type); 341 } 342 343 private StackValue genStatement(KtElement statement) { 344 return genQualified(StackValue.none(), statement, statementVisitor); 345 } 346 347 @Override 348 public StackValue visitClass(@NotNull KtClass klass, StackValue data) { 349 return visitClassOrObject(klass); 350 } 351 352 private StackValue visitClassOrObject(KtClassOrObject declaration) { 353 ClassDescriptor descriptor = bindingContext.get(CLASS, declaration); 354 assert descriptor != null; 355 356 Type asmType = asmTypeForAnonymousClass(bindingContext, declaration); 357 ClassBuilder classBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor), asmType, declaration.getContainingFile()); 358 359 ClassContext objectContext = context.intoAnonymousClass(descriptor, this, OwnerKind.IMPLEMENTATION); 360 new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state, getParentCodegen(), /* isLocal = */ true).generate(); 361 362 if (declaration instanceof KtClass && ((KtClass) declaration).isInterface()) { 363 Type traitImplType = state.getTypeMapper().mapDefaultImpls(descriptor); 364 ClassBuilder traitImplBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.TraitImpl(declaration, descriptor), traitImplType, declaration.getContainingFile()); 365 ClassContext traitImplContext = context.intoAnonymousClass(descriptor, this, OwnerKind.DEFAULT_IMPLS); 366 new InterfaceImplBodyCodegen(declaration, traitImplContext, traitImplBuilder, state, parentCodegen).generate(); 367 } 368 369 return StackValue.none(); 370 } 371 372 @Override 373 public StackValue visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, StackValue data) { 374 return visitClassOrObject(declaration); 375 } 376 377 @Override 378 public StackValue visitExpression(@NotNull KtExpression expression, StackValue receiver) { 379 throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented"); 380 } 381 382 @Override 383 public StackValue visitSuperExpression(@NotNull KtSuperExpression expression, StackValue data) { 384 return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, false); 385 } 386 387 @NotNull 388 public static ClassDescriptor getSuperCallLabelTarget( 389 @NotNull CodegenContext<?> context, 390 @NotNull KtSuperExpression expression 391 ) { 392 BindingContext bindingContext = context.getState().getBindingContext(); 393 PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel()); 394 ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi); 395 DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference()); 396 // "super<descriptor>@labelTarget" 397 if (labelTarget != null) { 398 return labelTarget; 399 } 400 assert descriptor instanceof ClassDescriptor : "Don't know how to generate super-call to not a class"; 401 CodegenContext result = getParentContextSubclassOf((ClassDescriptor) descriptor, context); 402 assert result != null : "Can't find parent context for " + descriptor; 403 return result.getThisDescriptor(); 404 } 405 406 @NotNull 407 private Type asmType(@NotNull KotlinType type) { 408 return typeMapper.mapType(type); 409 } 410 411 @NotNull 412 public Type expressionType(@Nullable KtExpression expression) { 413 KotlinType type = expressionJetType(expression); 414 return type == null ? Type.VOID_TYPE : asmType(type); 415 } 416 417 @Nullable 418 public KotlinType expressionJetType(@Nullable KtExpression expression) { 419 return expression != null ? bindingContext.getType(expression) : null; 420 } 421 422 @Override 423 public StackValue visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression, StackValue receiver) { 424 return genQualified(receiver, expression.getExpression()); 425 } 426 427 @Override 428 public StackValue visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, StackValue receiver) { 429 return genQualified(receiver, expression.getBaseExpression()); 430 } 431 432 private static boolean isEmptyExpression(@Nullable KtElement expr) { 433 if (expr == null) { 434 return true; 435 } 436 if (expr instanceof KtBlockExpression) { 437 KtBlockExpression blockExpression = (KtBlockExpression) expr; 438 List<KtExpression> statements = blockExpression.getStatements(); 439 if (statements.size() == 0 || statements.size() == 1 && isEmptyExpression(statements.get(0))) { 440 return true; 441 } 442 } 443 return false; 444 } 445 446 @Override 447 public StackValue visitIfExpression(@NotNull KtIfExpression expression, StackValue receiver) { 448 return generateIfExpression(expression, false); 449 } 450 451 /* package */ StackValue generateIfExpression(@NotNull final KtIfExpression expression, final boolean isStatement) { 452 final Type asmType = isStatement ? Type.VOID_TYPE : expressionType(expression); 453 final StackValue condition = gen(expression.getCondition()); 454 455 final KtExpression thenExpression = expression.getThen(); 456 final KtExpression elseExpression = expression.getElse(); 457 458 if (isEmptyExpression(thenExpression)) { 459 if (isEmptyExpression(elseExpression)) { 460 return StackValue.coercion(condition, asmType); 461 } 462 return generateSingleBranchIf(condition, expression, elseExpression, false, isStatement); 463 } 464 else { 465 if (isEmptyExpression(elseExpression)) { 466 return generateSingleBranchIf(condition, expression, thenExpression, true, isStatement); 467 } 468 } 469 470 return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() { 471 @Override 472 public Unit invoke(InstructionAdapter v) { 473 Label elseLabel = new Label(); 474 BranchedValue.Companion.condJump(condition, elseLabel, true, v); 475 476 Label end = new Label(); 477 478 gen(thenExpression, asmType); 479 480 v.goTo(end); 481 v.mark(elseLabel); 482 483 gen(elseExpression, asmType); 484 485 markLineNumber(expression, isStatement); 486 v.mark(end); 487 return Unit.INSTANCE; 488 } 489 }); 490 } 491 492 @Override 493 public StackValue visitWhileExpression(@NotNull KtWhileExpression expression, StackValue receiver) { 494 Label condition = new Label(); 495 v.mark(condition); 496 497 Label end = new Label(); 498 blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression))); 499 500 StackValue conditionValue = gen(expression.getCondition()); 501 BranchedValue.Companion.loopJump(conditionValue, end, true, v); 502 503 generateLoopBody(expression.getBody()); 504 505 v.goTo(condition); 506 507 v.mark(end); 508 509 blockStackElements.pop(); 510 511 return StackValue.onStack(Type.VOID_TYPE); 512 } 513 514 515 @Override 516 public StackValue visitDoWhileExpression(@NotNull KtDoWhileExpression expression, StackValue receiver) { 517 Label beginLoopLabel = new Label(); 518 v.mark(beginLoopLabel); 519 520 Label breakLabel = new Label(); 521 Label continueLabel = new Label(); 522 523 blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression))); 524 525 PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel); 526 527 KtExpression body = expression.getBody(); 528 KtExpression condition = expression.getCondition(); 529 StackValue conditionValue; 530 531 if (body instanceof KtBlockExpression) { 532 // If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop. 533 // We handle this case separately because otherwise such variable will be out of the frame map after the block ends 534 List<KtExpression> doWhileStatements = ((KtBlockExpression) body).getStatements(); 535 536 List<KtExpression> statements = new ArrayList<KtExpression>(doWhileStatements.size() + 1); 537 statements.addAll(doWhileStatements); 538 statements.add(condition); 539 540 conditionValue = generateBlock(statements, false, continueLabel, null); 541 } 542 else { 543 if (body != null) { 544 gen(body, Type.VOID_TYPE); 545 } 546 v.mark(continueLabel); 547 conditionValue = gen(condition); 548 } 549 550 BranchedValue.Companion.loopJump(conditionValue, beginLoopLabel, false, v); 551 v.mark(breakLabel); 552 553 blockStackElements.pop(); 554 return StackValue.none(); 555 } 556 557 @Override 558 public StackValue visitForExpression(@NotNull KtForExpression forExpression, StackValue receiver) { 559 // Is it a "1..2" or so 560 RangeCodegenUtil.BinaryCall binaryCall = RangeCodegenUtil.getRangeAsBinaryCall(forExpression); 561 if (binaryCall != null) { 562 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(binaryCall.op, bindingContext); 563 if (resolvedCall != null) { 564 if (RangeCodegenUtil.isOptimizableRangeTo(resolvedCall.getResultingDescriptor())) { 565 generateForLoop(new ForInRangeLiteralLoopGenerator(forExpression, binaryCall)); 566 return StackValue.none(); 567 } 568 } 569 } 570 571 KtExpression loopRange = forExpression.getLoopRange(); 572 assert loopRange != null; 573 KotlinType loopRangeType = bindingContext.getType(loopRange); 574 assert loopRangeType != null; 575 Type asmLoopRangeType = asmType(loopRangeType); 576 if (asmLoopRangeType.getSort() == Type.ARRAY) { 577 generateForLoop(new ForInArrayLoopGenerator(forExpression)); 578 return StackValue.none(); 579 } 580 581 if (RangeCodegenUtil.isRange(loopRangeType)) { 582 generateForLoop(new ForInRangeInstanceLoopGenerator(forExpression)); 583 return StackValue.none(); 584 } 585 586 if (RangeCodegenUtil.isProgression(loopRangeType)) { 587 generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression)); 588 return StackValue.none(); 589 } 590 591 generateForLoop(new IteratorForLoopGenerator(forExpression)); 592 return StackValue.none(); 593 } 594 595 private OwnerKind contextKind() { 596 return context.getContextKind(); 597 } 598 599 private void generateForLoop(AbstractForLoopGenerator generator) { 600 Label loopExit = new Label(); 601 Label loopEntry = new Label(); 602 Label continueLabel = new Label(); 603 604 generator.beforeLoop(); 605 generator.checkEmptyLoop(loopExit); 606 607 v.mark(loopEntry); 608 generator.checkPreCondition(loopExit); 609 610 // Some forms of for-loop can be optimized as post-condition loops. 611 PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel); 612 613 generator.beforeBody(); 614 blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.forExpression))); 615 generator.body(); 616 blockStackElements.pop(); 617 v.mark(continueLabel); 618 generator.afterBody(loopExit); 619 620 v.goTo(loopEntry); 621 622 v.mark(loopExit); 623 generator.afterLoop(); 624 } 625 626 private abstract class AbstractForLoopGenerator { 627 628 // for (e : E in c) {...} 629 protected final KtForExpression forExpression; 630 private final Label loopParameterStartLabel = new Label(); 631 private final Label bodyEnd = new Label(); 632 private final List<Runnable> leaveVariableTasks = Lists.newArrayList(); 633 634 protected final KotlinType elementType; 635 protected final Type asmElementType; 636 637 protected int loopParameterVar; 638 protected Type loopParameterType; 639 640 private AbstractForLoopGenerator(@NotNull KtForExpression forExpression) { 641 this.forExpression = forExpression; 642 this.elementType = getElementType(forExpression); 643 this.asmElementType = asmType(elementType); 644 } 645 646 @NotNull 647 private KotlinType getElementType(KtForExpression forExpression) { 648 KtExpression loopRange = forExpression.getLoopRange(); 649 assert loopRange != null; 650 ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext, 651 LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange, 652 "No next() function " + DiagnosticUtils.atLocation(loopRange)); 653 //noinspection ConstantConditions 654 return nextCall.getResultingDescriptor().getReturnType(); 655 } 656 657 public void beforeLoop() { 658 KtParameter loopParameter = forExpression.getLoopParameter(); 659 if (loopParameter != null) { 660 // E e = tmp<iterator>.next() 661 final VariableDescriptor parameterDescriptor = bindingContext.get(VALUE_PARAMETER, loopParameter); 662 loopParameterType = asmType(parameterDescriptor.getType()); 663 loopParameterVar = myFrameMap.enter(parameterDescriptor, loopParameterType); 664 scheduleLeaveVariable(new Runnable() { 665 @Override 666 public void run() { 667 myFrameMap.leave(parameterDescriptor); 668 v.visitLocalVariable(parameterDescriptor.getName().asString(), 669 loopParameterType.getDescriptor(), null, 670 loopParameterStartLabel, bodyEnd, 671 loopParameterVar); 672 } 673 }); 674 } 675 else { 676 KtDestructuringDeclaration multiParameter = forExpression.getDestructuringParameter(); 677 assert multiParameter != null; 678 679 // E tmp<e> = tmp<iterator>.next() 680 loopParameterType = asmElementType; 681 loopParameterVar = createLoopTempVariable(asmElementType); 682 } 683 } 684 685 public abstract void checkEmptyLoop(@NotNull Label loopExit); 686 687 public abstract void checkPreCondition(@NotNull Label loopExit); 688 689 public void beforeBody() { 690 assignToLoopParameter(); 691 v.mark(loopParameterStartLabel); 692 693 if (forExpression.getLoopParameter() == null) { 694 KtDestructuringDeclaration multiParameter = forExpression.getDestructuringParameter(); 695 assert multiParameter != null; 696 697 generateMultiVariables(multiParameter.getEntries()); 698 } 699 } 700 701 private void generateMultiVariables(List<KtDestructuringDeclarationEntry> entries) { 702 for (KtDestructuringDeclarationEntry variableDeclaration : entries) { 703 final VariableDescriptor componentDescriptor = bindingContext.get(VARIABLE, variableDeclaration); 704 705 @SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType()); 706 final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType); 707 final Label variableStartLabel = new Label(); 708 scheduleLeaveVariable(new Runnable() { 709 @Override 710 public void run() { 711 myFrameMap.leave(componentDescriptor); 712 v.visitLocalVariable(componentDescriptor.getName().asString(), 713 componentAsmType.getDescriptor(), null, 714 variableStartLabel, bodyEnd, 715 componentVarIndex); 716 } 717 }); 718 719 ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration); 720 assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); 721 Call call = makeFakeCall(new TransientReceiver(elementType)); 722 723 StackValue value = invokeFunction(call, resolvedCall, StackValue.local(loopParameterVar, asmElementType)); 724 StackValue.local(componentVarIndex, componentAsmType).store(value, v); 725 v.visitLabel(variableStartLabel); 726 } 727 } 728 729 protected abstract void assignToLoopParameter(); 730 731 protected abstract void increment(@NotNull Label loopExit); 732 733 public void body() { 734 generateLoopBody(forExpression.getBody()); 735 } 736 737 private void scheduleLeaveVariable(Runnable runnable) { 738 leaveVariableTasks.add(runnable); 739 } 740 741 protected int createLoopTempVariable(final Type type) { 742 int varIndex = myFrameMap.enterTemp(type); 743 scheduleLeaveVariable(new Runnable() { 744 @Override 745 public void run() { 746 myFrameMap.leaveTemp(type); 747 } 748 }); 749 return varIndex; 750 } 751 752 public void afterBody(@NotNull Label loopExit) { 753 markStartLineNumber(forExpression); 754 755 increment(loopExit); 756 757 v.mark(bodyEnd); 758 } 759 760 public void afterLoop() { 761 for (Runnable task : Lists.reverse(leaveVariableTasks)) { 762 task.run(); 763 } 764 } 765 766 // This method consumes range/progression from stack 767 // The result is stored to local variable 768 protected void generateRangeOrProgressionProperty(Type loopRangeType, String getterName, Type elementType, int varToStore) { 769 v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + elementType.getDescriptor(), false); 770 v.store(varToStore, elementType); 771 } 772 } 773 774 private void generateLoopBody(@Nullable KtExpression body) { 775 if (body != null) { 776 gen(body, Type.VOID_TYPE); 777 } 778 } 779 780 private class IteratorForLoopGenerator extends AbstractForLoopGenerator { 781 782 private int iteratorVarIndex; 783 private final ResolvedCall<FunctionDescriptor> iteratorCall; 784 private final ResolvedCall<FunctionDescriptor> nextCall; 785 private final Type asmTypeForIterator; 786 787 private IteratorForLoopGenerator(@NotNull KtForExpression forExpression) { 788 super(forExpression); 789 790 KtExpression loopRange = forExpression.getLoopRange(); 791 assert loopRange != null; 792 this.iteratorCall = getNotNull(bindingContext, 793 LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange, 794 "No .iterator() function " + DiagnosticUtils.atLocation(loopRange)); 795 796 KotlinType iteratorType = iteratorCall.getResultingDescriptor().getReturnType(); 797 assert iteratorType != null; 798 this.asmTypeForIterator = asmType(iteratorType); 799 800 this.nextCall = getNotNull(bindingContext, 801 LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange, 802 "No next() function " + DiagnosticUtils.atLocation(loopRange)); 803 } 804 805 @Override 806 public void beforeLoop() { 807 super.beforeLoop(); 808 809 // Iterator<E> tmp<iterator> = c.iterator() 810 811 iteratorVarIndex = createLoopTempVariable(asmTypeForIterator); 812 813 StackValue.local(iteratorVarIndex, asmTypeForIterator).store(invokeFunction(iteratorCall, StackValue.none()), v); 814 } 815 816 @Override 817 public void checkEmptyLoop(@NotNull Label loopExit) { 818 } 819 820 @Override 821 public void checkPreCondition(@NotNull Label loopExit) { 822 // tmp<iterator>.hasNext() 823 824 KtExpression loopRange = forExpression.getLoopRange(); 825 @SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext, 826 LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange, 827 "No hasNext() function " + DiagnosticUtils.atLocation(loopRange)); 828 @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); 829 StackValue result = invokeFunction(fakeCall, hasNextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator)); 830 result.put(result.type, v); 831 832 FunctionDescriptor hasNext = hasNextCall.getResultingDescriptor(); 833 KotlinType type = hasNext.getReturnType(); 834 assert type != null && KotlinTypeChecker.DEFAULT.isSubtypeOf(type, DescriptorUtilsKt.getBuiltIns(hasNext).getBooleanType()); 835 836 Type asmType = asmType(type); 837 StackValue.coerce(asmType, Type.BOOLEAN_TYPE, v); 838 v.ifeq(loopExit); 839 } 840 841 @Override 842 protected void assignToLoopParameter() { 843 @SuppressWarnings("ConstantConditions") Call fakeCall = 844 makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); 845 StackValue value = invokeFunction(fakeCall, nextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator)); 846 //noinspection ConstantConditions 847 StackValue.local(loopParameterVar, loopParameterType).store(value, v); 848 } 849 850 @Override 851 protected void increment(@NotNull Label loopExit) { 852 } 853 } 854 855 private class ForInArrayLoopGenerator extends AbstractForLoopGenerator { 856 private int indexVar; 857 private int arrayVar; 858 private final KotlinType loopRangeType; 859 860 private ForInArrayLoopGenerator(@NotNull KtForExpression forExpression) { 861 super(forExpression); 862 loopRangeType = bindingContext.getType(forExpression.getLoopRange()); 863 } 864 865 @Override 866 public void beforeLoop() { 867 super.beforeLoop(); 868 869 indexVar = createLoopTempVariable(Type.INT_TYPE); 870 871 KtExpression loopRange = forExpression.getLoopRange(); 872 StackValue value = gen(loopRange); 873 Type asmLoopRangeType = asmType(loopRangeType); 874 if (value instanceof StackValue.Local && value.type.equals(asmLoopRangeType)) { 875 arrayVar = ((StackValue.Local) value).index; // no need to copy local variable into another variable 876 } 877 else { 878 arrayVar = createLoopTempVariable(OBJECT_TYPE); 879 value.put(asmLoopRangeType, v); 880 v.store(arrayVar, OBJECT_TYPE); 881 } 882 883 v.iconst(0); 884 v.store(indexVar, Type.INT_TYPE); 885 } 886 887 @Override 888 public void checkEmptyLoop(@NotNull Label loopExit) { 889 } 890 891 @Override 892 public void checkPreCondition(@NotNull Label loopExit) { 893 v.load(indexVar, Type.INT_TYPE); 894 v.load(arrayVar, OBJECT_TYPE); 895 v.arraylength(); 896 v.ificmpge(loopExit); 897 } 898 899 @Override 900 protected void assignToLoopParameter() { 901 Type arrayElParamType; 902 if (KotlinBuiltIns.isArray(loopRangeType)) { 903 arrayElParamType = boxType(asmElementType); 904 } 905 else { 906 arrayElParamType = asmElementType; 907 } 908 909 v.load(arrayVar, OBJECT_TYPE); 910 v.load(indexVar, Type.INT_TYPE); 911 v.aload(arrayElParamType); 912 StackValue.onStack(arrayElParamType).put(asmElementType, v); 913 v.store(loopParameterVar, asmElementType); 914 } 915 916 @Override 917 protected void increment(@NotNull Label loopExit) { 918 v.iinc(indexVar, 1); 919 } 920 } 921 922 private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator { 923 protected int endVar; 924 925 private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) { 926 super(forExpression); 927 928 switch (asmElementType.getSort()) { 929 case Type.INT: 930 case Type.BYTE: 931 case Type.SHORT: 932 case Type.CHAR: 933 case Type.LONG: 934 break; 935 936 default: 937 throw new IllegalStateException("Unexpected range element type: " + asmElementType); 938 } 939 } 940 941 @Override 942 public void beforeLoop() { 943 super.beforeLoop(); 944 945 endVar = createLoopTempVariable(asmElementType); 946 } 947 948 protected void checkPostCondition(@NotNull Label loopExit) { 949 assert endVar != -1 : 950 "endVar must be allocated, endVar = " + endVar; 951 952 v.load(loopParameterVar, asmElementType); 953 v.load(endVar, asmElementType); 954 if (asmElementType.getSort() == Type.LONG) { 955 v.lcmp(); 956 v.ifeq(loopExit); 957 } 958 else { 959 v.ificmpeq(loopExit); 960 } 961 } 962 963 @Override 964 public void checkPreCondition(@NotNull Label loopExit) { 965 } 966 } 967 968 private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator { 969 private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) { 970 super(forExpression); 971 } 972 973 @Override 974 public void beforeLoop() { 975 super.beforeLoop(); 976 977 storeRangeStartAndEnd(); 978 } 979 980 protected abstract void storeRangeStartAndEnd(); 981 982 @Override 983 public void checkEmptyLoop(@NotNull Label loopExit) { 984 985 v.load(loopParameterVar, asmElementType); 986 v.load(endVar, asmElementType); 987 if (asmElementType.getSort() == Type.LONG) { 988 v.lcmp(); 989 v.ifgt(loopExit); 990 } 991 else { 992 v.ificmpgt(loopExit); 993 } 994 } 995 996 @Override 997 protected void assignToLoopParameter() { 998 } 999 1000 @Override 1001 protected void increment(@NotNull Label loopExit) { 1002 checkPostCondition(loopExit); 1003 1004 if (asmElementType == Type.INT_TYPE) { 1005 v.iinc(loopParameterVar, 1); 1006 } 1007 else { 1008 v.load(loopParameterVar, asmElementType); 1009 genIncrement(asmElementType, 1, v); 1010 v.store(loopParameterVar, asmElementType); 1011 } 1012 } 1013 } 1014 1015 private class ForInRangeLiteralLoopGenerator extends AbstractForInRangeLoopGenerator { 1016 private final RangeCodegenUtil.BinaryCall rangeCall; 1017 1018 private ForInRangeLiteralLoopGenerator( 1019 @NotNull KtForExpression forExpression, 1020 @NotNull RangeCodegenUtil.BinaryCall rangeCall 1021 ) { 1022 super(forExpression); 1023 this.rangeCall = rangeCall; 1024 } 1025 1026 @Override 1027 protected void storeRangeStartAndEnd() { 1028 gen(rangeCall.left, asmElementType); 1029 v.store(loopParameterVar, asmElementType); 1030 1031 gen(rangeCall.right, asmElementType); 1032 v.store(endVar, asmElementType); 1033 } 1034 } 1035 1036 private class ForInRangeInstanceLoopGenerator extends AbstractForInRangeLoopGenerator { 1037 private ForInRangeInstanceLoopGenerator(@NotNull KtForExpression forExpression) { 1038 super(forExpression); 1039 } 1040 1041 @Override 1042 protected void storeRangeStartAndEnd() { 1043 KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange()); 1044 assert loopRangeType != null; 1045 Type asmLoopRangeType = asmType(loopRangeType); 1046 gen(forExpression.getLoopRange(), asmLoopRangeType); 1047 v.dup(); 1048 1049 // ranges inherit first and last from corresponding progressions 1050 generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterVar); 1051 generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, endVar); 1052 } 1053 } 1054 1055 private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator { 1056 private int incrementVar; 1057 private Type incrementType; 1058 1059 private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) { 1060 super(forExpression); 1061 } 1062 1063 @Override 1064 public void beforeLoop() { 1065 super.beforeLoop(); 1066 1067 incrementVar = createLoopTempVariable(asmElementType); 1068 1069 KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange()); 1070 assert loopRangeType != null; 1071 Type asmLoopRangeType = asmType(loopRangeType); 1072 1073 Collection<PropertyDescriptor> incrementProp = 1074 loopRangeType.getMemberScope().getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND); 1075 assert incrementProp.size() == 1 : loopRangeType + " " + incrementProp.size(); 1076 incrementType = asmType(incrementProp.iterator().next().getType()); 1077 1078 gen(forExpression.getLoopRange(), asmLoopRangeType); 1079 v.dup(); 1080 v.dup(); 1081 1082 generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterVar); 1083 generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, endVar); 1084 generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementVar); 1085 } 1086 1087 @Override 1088 public void checkEmptyLoop(@NotNull Label loopExit) { 1089 1090 v.load(loopParameterVar, asmElementType); 1091 v.load(endVar, asmElementType); 1092 v.load(incrementVar, incrementType); 1093 1094 Label negativeIncrement = new Label(); 1095 Label afterIf = new Label(); 1096 1097 if (asmElementType.getSort() == Type.LONG) { 1098 v.lconst(0L); 1099 v.lcmp(); 1100 v.ifle(negativeIncrement); // if increment < 0, jump 1101 1102 // increment > 0 1103 v.lcmp(); 1104 v.ifgt(loopExit); 1105 v.goTo(afterIf); 1106 1107 // increment < 0 1108 v.mark(negativeIncrement); 1109 v.lcmp(); 1110 v.iflt(loopExit); 1111 v.mark(afterIf); 1112 } 1113 else { 1114 v.ifle(negativeIncrement); // if increment < 0, jump 1115 1116 // increment > 0 1117 v.ificmpgt(loopExit); 1118 v.goTo(afterIf); 1119 1120 // increment < 0 1121 v.mark(negativeIncrement); 1122 v.ificmplt(loopExit); 1123 v.mark(afterIf); 1124 } 1125 } 1126 1127 @Override 1128 protected void assignToLoopParameter() { 1129 } 1130 1131 @Override 1132 protected void increment(@NotNull Label loopExit) { 1133 checkPostCondition(loopExit); 1134 1135 v.load(loopParameterVar, asmElementType); 1136 v.load(incrementVar, asmElementType); 1137 v.add(asmElementType); 1138 1139 if (asmElementType == Type.BYTE_TYPE || asmElementType == Type.SHORT_TYPE || asmElementType == Type.CHAR_TYPE) { 1140 StackValue.coerce(Type.INT_TYPE, asmElementType, v); 1141 } 1142 1143 v.store(loopParameterVar, asmElementType); 1144 } 1145 } 1146 1147 1148 @Override 1149 public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) { 1150 return generateBreakOrContinueExpression(expression, true, new Label()); 1151 } 1152 1153 @Override 1154 public StackValue visitContinueExpression(@NotNull KtContinueExpression expression, StackValue receiver) { 1155 return generateBreakOrContinueExpression(expression, false, new Label()); 1156 } 1157 1158 @NotNull 1159 private StackValue generateBreakOrContinueExpression( 1160 @NotNull KtExpressionWithLabel expression, 1161 boolean isBreak, 1162 final @NotNull Label afterBreakContinueLabel 1163 ) { 1164 assert expression instanceof KtContinueExpression || expression instanceof KtBreakExpression; 1165 1166 if (!blockStackElements.isEmpty()) { 1167 BlockStackElement stackElement = blockStackElements.peek(); 1168 1169 if (stackElement instanceof FinallyBlockStackElement) { 1170 FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement; 1171 //noinspection ConstantConditions 1172 genFinallyBlockOrGoto(finallyBlockStackElement, null, afterBreakContinueLabel); 1173 } 1174 else if (stackElement instanceof LoopBlockStackElement) { 1175 LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement; 1176 KtSimpleNameExpression labelElement = expression.getTargetLabel(); 1177 //noinspection ConstantConditions 1178 if (labelElement == null || 1179 loopBlockStackElement.targetLabel != null && 1180 labelElement.getReferencedName().equals(loopBlockStackElement.targetLabel.getReferencedName())) { 1181 final Label label = isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel; 1182 return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() { 1183 @Override 1184 public Unit invoke(InstructionAdapter adapter) { 1185 PseudoInsnsKt.fixStackAndJump(v, label); 1186 v.mark(afterBreakContinueLabel); 1187 return Unit.INSTANCE; 1188 } 1189 } 1190 ); 1191 } 1192 } 1193 else { 1194 throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack"); 1195 } 1196 1197 blockStackElements.pop(); 1198 StackValue result = generateBreakOrContinueExpression(expression, isBreak, afterBreakContinueLabel); 1199 blockStackElements.push(stackElement); 1200 return result; 1201 } 1202 1203 throw new UnsupportedOperationException("Target label for break/continue not found"); 1204 } 1205 1206 private StackValue generateSingleBranchIf( 1207 final StackValue condition, 1208 final KtIfExpression ifExpression, 1209 final KtExpression expression, 1210 final boolean inverse, 1211 final boolean isStatement 1212 ) { 1213 Type targetType = isStatement ? Type.VOID_TYPE : expressionType(ifExpression); 1214 return StackValue.operation(targetType, new Function1<InstructionAdapter, Unit>() { 1215 @Override 1216 public Unit invoke(InstructionAdapter v) { 1217 Label elseLabel = new Label(); 1218 BranchedValue.Companion.condJump(condition, elseLabel, inverse, v); 1219 1220 if (isStatement) { 1221 gen(expression, Type.VOID_TYPE); 1222 v.mark(elseLabel); 1223 } 1224 else { 1225 Type targetType = expressionType(ifExpression); 1226 gen(expression, targetType); 1227 Label end = new Label(); 1228 v.goTo(end); 1229 1230 v.mark(elseLabel); 1231 StackValue.putUnitInstance(v); 1232 1233 markStartLineNumber(ifExpression); 1234 v.mark(end); 1235 } 1236 return null; 1237 } 1238 }); 1239 } 1240 1241 @Override 1242 public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) { 1243 ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext); 1244 assert compileTimeValue != null; 1245 return StackValue.constant(compileTimeValue.getValue(), expressionType(expression)); 1246 } 1247 1248 @Nullable 1249 public static ConstantValue<?> getPrimitiveOrStringCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) { 1250 ConstantValue<?> constant = getCompileTimeConstant(expression, bindingContext, false); 1251 if (constant == null || ConstantExpressionEvaluatorKt.isStandaloneOnlyConstant(constant)) { 1252 return null; 1253 } 1254 return constant; 1255 } 1256 1257 @Nullable 1258 public static ConstantValue<?> getCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) { 1259 return getCompileTimeConstant(expression, bindingContext, false); 1260 } 1261 1262 @Nullable 1263 public static ConstantValue<?> getCompileTimeConstant( 1264 @NotNull KtExpression expression, 1265 @NotNull final BindingContext bindingContext, 1266 boolean takeUpConstValsAsConst 1267 ) { 1268 CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext); 1269 if (compileTimeValue == null || compileTimeValue.getUsesNonConstValAsConstant()) { 1270 return null; 1271 } 1272 1273 if (!takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) { 1274 final Ref<Boolean> containsNonInlinedVals = new Ref<Boolean>(false); 1275 KtVisitor constantChecker = new KtVisitor() { 1276 @Override 1277 public Object visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, Object data) { 1278 ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext); 1279 if (resolvedCall != null) { 1280 CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor(); 1281 if (callableDescriptor instanceof PropertyDescriptor && 1282 !JvmCodegenUtil.isInlinedJavaConstProperty((VariableDescriptor) callableDescriptor)) { 1283 containsNonInlinedVals.set(true); 1284 } 1285 } 1286 return null; 1287 } 1288 1289 @Override 1290 public Object visitKtElement(@NotNull KtElement element, Object data) { 1291 if (!containsNonInlinedVals.get()) { 1292 element.acceptChildren(this); 1293 } 1294 return null; 1295 } 1296 }; 1297 1298 expression.accept(constantChecker); 1299 1300 if (containsNonInlinedVals.get()) { 1301 return null; 1302 } 1303 } 1304 1305 KotlinType expectedType = bindingContext.getType(expression); 1306 return compileTimeValue.toConstantValue(expectedType); 1307 } 1308 1309 @Override 1310 public StackValue visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, StackValue receiver) { 1311 StringBuilder constantValue = new StringBuilder(""); 1312 final KtStringTemplateEntry[] entries = expression.getEntries(); 1313 1314 if (entries.length == 1 && entries[0] instanceof KtStringTemplateEntryWithExpression) { 1315 KtExpression expr = entries[0].getExpression(); 1316 return genToString(gen(expr), expressionType(expr)); 1317 } 1318 1319 for (KtStringTemplateEntry entry : entries) { 1320 if (entry instanceof KtLiteralStringTemplateEntry) { 1321 constantValue.append(entry.getText()); 1322 } 1323 else if (entry instanceof KtEscapeStringTemplateEntry) { 1324 constantValue.append(((KtEscapeStringTemplateEntry) entry).getUnescapedValue()); 1325 } 1326 else { 1327 constantValue = null; 1328 break; 1329 } 1330 } 1331 if (constantValue != null) { 1332 Type type = expressionType(expression); 1333 return StackValue.constant(constantValue.toString(), type); 1334 } 1335 else { 1336 return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() { 1337 @Override 1338 public Unit invoke(InstructionAdapter v) { 1339 genStringBuilderConstructor(v); 1340 for (KtStringTemplateEntry entry : entries) { 1341 if (entry instanceof KtStringTemplateEntryWithExpression) { 1342 invokeAppend(entry.getExpression()); 1343 } 1344 else { 1345 String text = entry instanceof KtEscapeStringTemplateEntry 1346 ? ((KtEscapeStringTemplateEntry) entry).getUnescapedValue() 1347 : entry.getText(); 1348 v.aconst(text); 1349 genInvokeAppendMethod(v, JAVA_STRING_TYPE); 1350 } 1351 } 1352 v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); 1353 return Unit.INSTANCE; 1354 } 1355 }); 1356 } 1357 } 1358 1359 @Override 1360 public StackValue visitBlockExpression(@NotNull KtBlockExpression expression, StackValue receiver) { 1361 return generateBlock(expression, false); 1362 } 1363 1364 @Override 1365 public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data) { 1366 return visitNamedFunction(function, data, false); 1367 } 1368 1369 public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data, boolean isStatement) { 1370 assert data == StackValue.none(); 1371 1372 if (KtPsiUtil.isScriptDeclaration(function)) { 1373 return StackValue.none(); 1374 } 1375 1376 StackValue closure = genClosure(function, null); 1377 if (isStatement) { 1378 DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); 1379 int index = lookupLocalIndex(descriptor); 1380 closure.put(OBJECT_TYPE, v); 1381 v.store(index, OBJECT_TYPE); 1382 return StackValue.none(); 1383 } 1384 else { 1385 return closure; 1386 } 1387 } 1388 1389 @Override 1390 public StackValue visitLambdaExpression(@NotNull KtLambdaExpression expression, StackValue receiver) { 1391 if (Boolean.TRUE.equals(bindingContext.get(BLOCK, expression))) { 1392 return gen(expression.getFunctionLiteral().getBodyExpression()); 1393 } 1394 else { 1395 return genClosure(expression.getFunctionLiteral(), null); 1396 } 1397 } 1398 1399 @NotNull 1400 private StackValue genClosure(KtDeclarationWithBody declaration, @Nullable SamType samType) { 1401 FunctionDescriptor descriptor = bindingContext.get(FUNCTION, declaration); 1402 assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText(); 1403 1404 return genClosure( 1405 declaration, descriptor, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), samType, null 1406 ); 1407 } 1408 1409 @NotNull 1410 private StackValue genClosure( 1411 @NotNull KtElement declaration, 1412 @NotNull FunctionDescriptor descriptor, 1413 @NotNull FunctionGenerationStrategy strategy, 1414 @Nullable SamType samType, 1415 @Nullable FunctionDescriptor functionReferenceTarget 1416 ) { 1417 ClassBuilder cv = state.getFactory().newVisitor( 1418 JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor), 1419 asmTypeForAnonymousClass(bindingContext, descriptor), 1420 declaration.getContainingFile() 1421 ); 1422 1423 ClosureCodegen closureCodegen = new ClosureCodegen( 1424 state, declaration, samType, context.intoClosure(descriptor, this, typeMapper), 1425 functionReferenceTarget, strategy, parentCodegen, cv 1426 ); 1427 1428 closureCodegen.generate(); 1429 1430 if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) { 1431 ReifiedTypeInliner.putNeedClassReificationMarker(v); 1432 propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages()); 1433 } 1434 1435 return closureCodegen.putInstanceOnStack(this); 1436 } 1437 1438 @Override 1439 public StackValue visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, StackValue receiver) { 1440 final ObjectLiteralResult objectLiteralResult = generateObjectLiteral(expression); 1441 final ClassDescriptor classDescriptor = objectLiteralResult.classDescriptor; 1442 final Type type = typeMapper.mapType(classDescriptor); 1443 1444 return StackValue.operation(type, new Function1<InstructionAdapter, Unit>() { 1445 @Override 1446 public Unit invoke(InstructionAdapter v) { 1447 if (objectLiteralResult.wereReifiedMarkers) { 1448 ReifiedTypeInliner.putNeedClassReificationMarker(v); 1449 } 1450 v.anew(type); 1451 v.dup(); 1452 1453 pushClosureOnStack(classDescriptor, true, defaultCallGenerator); 1454 1455 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); 1456 assert primaryConstructor != null : "There should be primary constructor for object literal"; 1457 ResolvedCall<ConstructorDescriptor> superCall = getDelegationConstructorCall(bindingContext, primaryConstructor); 1458 if (superCall != null) { 1459 // For an anonymous object, we should also generate all non-default arguments that it captures for its super call 1460 ConstructorDescriptor superConstructor = superCall.getResultingDescriptor(); 1461 ConstructorDescriptor constructorToCall = SamCodegenUtil.resolveSamAdapter(superConstructor); 1462 List<ValueParameterDescriptor> superValueParameters = superConstructor.getValueParameters(); 1463 int params = superValueParameters.size(); 1464 List<Type> superMappedTypes = typeMapper.mapToCallableMethod(constructorToCall, false).getValueParameterTypes(); 1465 assert superMappedTypes.size() >= params : String 1466 .format("Incorrect number of mapped parameters vs arguments: %d < %d for %s", 1467 superMappedTypes.size(), params, classDescriptor); 1468 1469 List<ResolvedValueArgument> valueArguments = new ArrayList<ResolvedValueArgument>(params); 1470 List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(params); 1471 List<Type> mappedTypes = new ArrayList<Type>(params); 1472 for (ValueParameterDescriptor parameter : superValueParameters) { 1473 ResolvedValueArgument argument = superCall.getValueArguments().get(parameter); 1474 if (!(argument instanceof DefaultValueArgument)) { 1475 valueArguments.add(argument); 1476 valueParameters.add(parameter); 1477 mappedTypes.add(superMappedTypes.get(parameter.getIndex())); 1478 } 1479 } 1480 ArgumentGenerator argumentGenerator = 1481 new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes); 1482 1483 argumentGenerator.generate(valueArguments, valueArguments); 1484 } 1485 1486 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); 1487 assert constructors.size() == 1 : "Unexpected number of constructors for class: " + classDescriptor + " " + constructors; 1488 ConstructorDescriptor constructorDescriptor = CollectionsKt.single(constructors); 1489 1490 Method constructor = typeMapper.mapAsmMethod(SamCodegenUtil.resolveSamAdapter(constructorDescriptor)); 1491 v.invokespecial(type.getInternalName(), "<init>", constructor.getDescriptor(), false); 1492 return Unit.INSTANCE; 1493 } 1494 }); 1495 } 1496 1497 public void pushClosureOnStack(@NotNull ClassDescriptor classDescriptor, boolean putThis, @NotNull CallGenerator callGenerator) { 1498 CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); 1499 if (closure == null) return; 1500 1501 int paramIndex = 0; 1502 1503 if (putThis) { 1504 ClassDescriptor captureThis = closure.getCaptureThis(); 1505 if (captureThis != null) { 1506 StackValue thisOrOuter = generateThisOrOuter(captureThis, false); 1507 assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type; 1508 callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++); 1509 } 1510 } 1511 1512 KotlinType captureReceiver = closure.getCaptureReceiverType(); 1513 if (captureReceiver != null) { 1514 Type asmType = typeMapper.mapType(captureReceiver); 1515 StackValue.Local capturedReceiver = StackValue.local(AsmUtil.getReceiverIndex(context, context.getContextDescriptor()), asmType); 1516 callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++); 1517 } 1518 1519 for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) { 1520 Type sharedVarType = typeMapper.getSharedVarType(entry.getKey()); 1521 if (sharedVarType == null) { 1522 sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey()); 1523 } 1524 StackValue capturedVar = lookupOuterValue(entry.getValue()); 1525 callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++); 1526 } 1527 1528 1529 ClassDescriptor superClass = DescriptorUtilsKt.getSuperClassNotAny(classDescriptor); 1530 if (superClass != null) { 1531 pushClosureOnStack( 1532 superClass, 1533 putThis && closure.getCaptureThis() == null, 1534 callGenerator 1535 ); 1536 } 1537 } 1538 1539 /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) { 1540 if (expression.getParent() instanceof KtNamedFunction) { 1541 // For functions end of block should be end of function label 1542 return generateBlock(expression.getStatements(), isStatement, null, context.getMethodEndLabel()); 1543 } 1544 return generateBlock(expression.getStatements(), isStatement, null, null); 1545 } 1546 1547 @NotNull 1548 public StackValue lookupOuterValue(EnclosedValueDescriptor d) { 1549 DeclarationDescriptor descriptor = d.getDescriptor(); 1550 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { 1551 if (aCase.isCase(descriptor)) { 1552 return aCase.outerValue(d, this); 1553 } 1554 } 1555 throw new IllegalStateException("Can't get outer value in " + this + " for " + d); 1556 } 1557 1558 private StackValue generateBlock( 1559 List<KtExpression> statements, 1560 boolean isStatement, 1561 Label labelBeforeLastExpression, 1562 @Nullable final Label labelBlockEnd 1563 ) { 1564 final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label(); 1565 1566 final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList(); 1567 1568 StackValue answer = StackValue.none(); 1569 1570 for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) { 1571 KtExpression possiblyLabeledStatement = iterator.next(); 1572 1573 KtElement statement = KtPsiUtil.safeDeparenthesize(possiblyLabeledStatement); 1574 1575 if (statement instanceof KtNamedDeclaration) { 1576 KtNamedDeclaration declaration = (KtNamedDeclaration) statement; 1577 if (KtPsiUtil.isScriptDeclaration(declaration)) { 1578 continue; 1579 } 1580 } 1581 1582 putDescriptorIntoFrameMap(statement); 1583 1584 boolean isExpression = !iterator.hasNext() && !isStatement; 1585 if (isExpression && labelBeforeLastExpression != null) { 1586 v.mark(labelBeforeLastExpression); 1587 } 1588 1589 StackValue result = isExpression ? gen(possiblyLabeledStatement) : genStatement(possiblyLabeledStatement); 1590 1591 if (!iterator.hasNext()) { 1592 answer = result; 1593 } 1594 else { 1595 result.put(Type.VOID_TYPE, v); 1596 } 1597 1598 addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks); 1599 } 1600 1601 return new StackValueWithLeaveTask(answer, new Function1<StackValue, Unit>() { 1602 @Override 1603 public Unit invoke(StackValue value) { 1604 if (labelBlockEnd == null) { 1605 v.mark(blockEnd); 1606 } 1607 for (Function<StackValue, Void> task : Lists.reverse(leaveTasks)) { 1608 task.fun(value); 1609 } 1610 return Unit.INSTANCE; 1611 } 1612 }); 1613 } 1614 1615 @NotNull 1616 private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) { 1617 Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); 1618 return sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType()); 1619 } 1620 1621 private static boolean isSharedVarType(@NotNull Type type) { 1622 return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX); 1623 } 1624 1625 1626 private void putDescriptorIntoFrameMap(@NotNull KtElement statement) { 1627 if (statement instanceof KtDestructuringDeclaration) { 1628 KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement; 1629 for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) { 1630 putLocalVariableIntoFrameMap(entry); 1631 } 1632 } 1633 1634 if (statement instanceof KtVariableDeclaration) { 1635 putLocalVariableIntoFrameMap((KtVariableDeclaration) statement); 1636 } 1637 1638 if (statement instanceof KtNamedFunction) { 1639 DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement); 1640 assert descriptor instanceof FunctionDescriptor : "Couldn't find function declaration in binding context " + statement.getText(); 1641 Type type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 1642 myFrameMap.enter(descriptor, type); 1643 } 1644 } 1645 1646 private void putLocalVariableIntoFrameMap(@NotNull KtVariableDeclaration statement) { 1647 VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement); 1648 assert variableDescriptor != null : "Couldn't find variable declaration in binding context " + statement.getText(); 1649 1650 Type type = getVariableType(variableDescriptor); 1651 int index = myFrameMap.enter(variableDescriptor, type); 1652 1653 if (isSharedVarType(type)) { 1654 markLineNumber(statement, false); 1655 v.anew(type); 1656 v.dup(); 1657 v.invokespecial(type.getInternalName(), "<init>", "()V", false); 1658 v.store(index, OBJECT_TYPE); 1659 } 1660 } 1661 1662 private void addLeaveTaskToRemoveDescriptorFromFrameMap( 1663 @NotNull KtElement statement, 1664 @NotNull Label blockEnd, 1665 @NotNull List<Function<StackValue, Void>> leaveTasks 1666 ) { 1667 if (statement instanceof KtDestructuringDeclaration) { 1668 KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement; 1669 for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) { 1670 addLeaveTaskToRemoveLocalVariableFromFrameMap(entry, blockEnd, leaveTasks); 1671 } 1672 } 1673 1674 if (statement instanceof KtVariableDeclaration) { 1675 addLeaveTaskToRemoveLocalVariableFromFrameMap((KtVariableDeclaration) statement, blockEnd, leaveTasks); 1676 } 1677 1678 if (statement instanceof KtNamedFunction) { 1679 addLeaveTaskToRemoveNamedFunctionFromFrameMap((KtNamedFunction) statement, blockEnd, leaveTasks); 1680 } 1681 } 1682 1683 private void addLeaveTaskToRemoveLocalVariableFromFrameMap( 1684 @NotNull KtVariableDeclaration statement, 1685 final Label blockEnd, 1686 @NotNull List<Function<StackValue, Void>> leaveTasks 1687 ) { 1688 final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement); 1689 assert variableDescriptor != null; 1690 1691 final Type type = getVariableType(variableDescriptor); 1692 1693 final Label scopeStart = new Label(); 1694 v.mark(scopeStart); 1695 1696 leaveTasks.add(new Function<StackValue, Void>() { 1697 @Override 1698 public Void fun(StackValue answer) { 1699 int index = myFrameMap.leave(variableDescriptor); 1700 1701 if (isSharedVarType(type)) { 1702 v.aconst(null); 1703 v.store(index, OBJECT_TYPE); 1704 } 1705 v.visitLocalVariable(variableDescriptor.getName().asString(), type.getDescriptor(), null, scopeStart, blockEnd, index); 1706 return null; 1707 } 1708 }); 1709 } 1710 1711 private void addLeaveTaskToRemoveNamedFunctionFromFrameMap( 1712 @NotNull final KtNamedFunction statement, 1713 final Label blockEnd, 1714 @NotNull List<Function<StackValue, Void>> leaveTasks 1715 ) { 1716 final FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement); 1717 assert functionDescriptor != null; 1718 1719 final Type type = asmTypeForAnonymousClass(bindingContext, functionDescriptor); 1720 1721 final Label scopeStart = new Label(); 1722 v.mark(scopeStart); 1723 1724 leaveTasks.add(new Function<StackValue, Void>() { 1725 @Override 1726 public Void fun(StackValue answer) { 1727 int index = myFrameMap.leave(functionDescriptor); 1728 1729 assert !functionDescriptor.getName().isSpecial() : "Local variable should be generated only for function with name: " + statement.getText(); 1730 v.visitLocalVariable(functionDescriptor.getName().asString() + "$", type.getDescriptor(), null, scopeStart, blockEnd, index); 1731 return null; 1732 } 1733 }); 1734 } 1735 1736 public boolean isShouldMarkLineNumbers() { 1737 return shouldMarkLineNumbers; 1738 } 1739 1740 public void setShouldMarkLineNumbers(boolean shouldMarkLineNumbers) { 1741 this.shouldMarkLineNumbers = shouldMarkLineNumbers; 1742 } 1743 1744 public void markStartLineNumber(@NotNull KtElement element) { 1745 markLineNumber(element, false); 1746 } 1747 1748 public void markLineNumber(@NotNull KtElement statement, boolean markEndOffset) { 1749 if (!shouldMarkLineNumbers) return; 1750 1751 Integer lineNumber = CodegenUtil.getLineNumberForElement(statement, markEndOffset); 1752 if (lineNumber == null || lineNumber == myLastLineNumber) { 1753 return; 1754 } 1755 myLastLineNumber = lineNumber; 1756 1757 Label label = new Label(); 1758 v.visitLabel(label); 1759 v.visitLineNumber(lineNumber, label); 1760 } 1761 1762 //we should generate additional linenumber info after inline call only if it used as argument 1763 public void markLineNumberAfterInlineIfNeeded() { 1764 if (!shouldMarkLineNumbers) { 1765 //if it used as general argument 1766 if (myLastLineNumber > -1) { 1767 Label label = new Label(); 1768 v.visitLabel(label); 1769 v.visitLineNumber(myLastLineNumber, label); 1770 } 1771 } else { 1772 //if it used as argument of infix call (in this case lineNumber for simple inlineCall also would be reset) 1773 myLastLineNumber = -1; 1774 } 1775 } 1776 1777 public int getLastLineNumber() { 1778 return myLastLineNumber; 1779 } 1780 1781 private void doFinallyOnReturn(@NotNull Label afterReturnLabel) { 1782 if(!blockStackElements.isEmpty()) { 1783 BlockStackElement stackElement = blockStackElements.peek(); 1784 if (stackElement instanceof FinallyBlockStackElement) { 1785 FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement; 1786 genFinallyBlockOrGoto(finallyBlockStackElement, null, afterReturnLabel); 1787 } 1788 else if (stackElement instanceof LoopBlockStackElement) { 1789 1790 } else { 1791 throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack"); 1792 } 1793 1794 blockStackElements.pop(); 1795 doFinallyOnReturn(afterReturnLabel); 1796 blockStackElements.push(stackElement); 1797 } 1798 } 1799 1800 public boolean hasFinallyBlocks() { 1801 for (BlockStackElement element : blockStackElements) { 1802 if (element instanceof FinallyBlockStackElement) { 1803 return true; 1804 } 1805 } 1806 return false; 1807 } 1808 1809 private void genFinallyBlockOrGoto( 1810 @Nullable FinallyBlockStackElement finallyBlockStackElement, 1811 @Nullable Label tryCatchBlockEnd, 1812 @Nullable Label afterJumpLabel 1813 ) { 1814 if (finallyBlockStackElement != null) { 1815 finallyDepth++; 1816 assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent"; 1817 1818 BlockStackElement topOfStack = blockStackElements.pop(); 1819 assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block"; 1820 1821 KtTryExpression jetTryExpression = finallyBlockStackElement.expression; 1822 Label finallyStart = new Label(); 1823 v.mark(finallyStart); 1824 finallyBlockStackElement.addGapLabel(finallyStart); 1825 if (InlineCodegenUtil.isFinallyMarkerRequired(context)) { 1826 InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, true); 1827 } 1828 //noinspection ConstantConditions 1829 gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE); 1830 1831 if (InlineCodegenUtil.isFinallyMarkerRequired(context)) { 1832 InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, false); 1833 } 1834 } 1835 1836 if (tryCatchBlockEnd != null) { 1837 v.goTo(tryCatchBlockEnd); 1838 } 1839 1840 if (finallyBlockStackElement != null) { 1841 finallyDepth--; 1842 Label finallyEnd = afterJumpLabel != null ? afterJumpLabel : new Label(); 1843 if (afterJumpLabel == null) { 1844 v.mark(finallyEnd); 1845 } 1846 finallyBlockStackElement.addGapLabel(finallyEnd); 1847 1848 blockStackElements.push(finallyBlockStackElement); 1849 } 1850 } 1851 1852 @Override 1853 public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, StackValue receiver) { 1854 return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() { 1855 @Override 1856 public Unit invoke(InstructionAdapter adapter) { 1857 KtExpression returnedExpression = expression.getReturnedExpression(); 1858 CallableMemberDescriptor descriptor = getContext().getContextDescriptor(); 1859 NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression); 1860 boolean isNonLocalReturn = nonLocalReturn != null; 1861 if (isNonLocalReturn && !state.isInlineEnabled()) { 1862 state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression)); 1863 genThrow(v, "java/lang/UnsupportedOperationException", 1864 "Non-local returns are not allowed with inlining disabled"); 1865 return Unit.INSTANCE; 1866 } 1867 1868 Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : ExpressionCodegen.this.returnType; 1869 if (returnedExpression != null) { 1870 gen(returnedExpression, returnType); 1871 } 1872 1873 Label afterReturnLabel = new Label(); 1874 generateFinallyBlocksIfNeeded(returnType, afterReturnLabel); 1875 1876 if (isNonLocalReturn) { 1877 InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName); 1878 } 1879 v.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); 1880 v.mark(afterReturnLabel); 1881 return Unit.INSTANCE; 1882 } 1883 }); 1884 } 1885 1886 public void generateFinallyBlocksIfNeeded(Type returnType, @NotNull Label afterReturnLabel) { 1887 if (hasFinallyBlocks()) { 1888 if (!Type.VOID_TYPE.equals(returnType)) { 1889 int returnValIndex = myFrameMap.enterTemp(returnType); 1890 StackValue.Local localForReturnValue = StackValue.local(returnValIndex, returnType); 1891 localForReturnValue.store(StackValue.onStack(returnType), v); 1892 doFinallyOnReturn(afterReturnLabel); 1893 localForReturnValue.put(returnType, v); 1894 myFrameMap.leaveTemp(returnType); 1895 } 1896 else { 1897 doFinallyOnReturn(afterReturnLabel); 1898 } 1899 } 1900 } 1901 1902 @Nullable 1903 private NonLocalReturnInfo getNonLocalReturnInfo(@NotNull CallableMemberDescriptor descriptor, @NotNull KtReturnExpression expression) { 1904 //call inside lambda 1905 if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) { 1906 if (expression.getLabelName() == null) { 1907 if (isFunctionLiteral(descriptor)) { 1908 //non labeled return couldn't be local in lambda 1909 FunctionDescriptor containingFunction = 1910 BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst(); 1911 //FIRST_FUN_LABEL to prevent clashing with existing labels 1912 return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL); 1913 } else { 1914 //local 1915 return null; 1916 } 1917 } 1918 1919 PsiElement element = bindingContext.get(LABEL_TARGET, expression.getTargetLabel()); 1920 if (element != DescriptorToSourceUtils.getSourceFromDescriptor(context.getContextDescriptor())) { 1921 DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element); 1922 assert element != null : "Expression should be not null " + expression.getText(); 1923 assert elementDescriptor != null : "Descriptor should be not null: " + element.getText(); 1924 return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName()); 1925 } 1926 } 1927 return null; 1928 } 1929 1930 public void returnExpression(KtExpression expr) { 1931 boolean isBlockedNamedFunction = expr instanceof KtBlockExpression && expr.getParent() instanceof KtNamedFunction; 1932 1933 // If generating body for named block-bodied function, generate it as sequence of statements 1934 gen(expr, isBlockedNamedFunction ? Type.VOID_TYPE : returnType); 1935 1936 // If it does not end with return we should return something 1937 // because if we don't there can be VerifyError (specific cases with Nothing-typed expressions) 1938 if (!endsWithReturn(expr)) { 1939 markLineNumber(expr, true); 1940 1941 if (isLambdaVoidBody(expr, returnType)) { 1942 markLineNumber((KtFunctionLiteral) expr.getParent(), true); 1943 } 1944 1945 if (isBlockedNamedFunction && !Type.VOID_TYPE.equals(expressionType(expr))) { 1946 StackValue.none().put(returnType, v); 1947 } 1948 1949 v.areturn(returnType); 1950 } 1951 } 1952 1953 private static boolean endsWithReturn(KtElement bodyExpression) { 1954 if (bodyExpression instanceof KtBlockExpression) { 1955 List<KtExpression> statements = ((KtBlockExpression) bodyExpression).getStatements(); 1956 return statements.size() > 0 && statements.get(statements.size() - 1) instanceof KtReturnExpression; 1957 } 1958 1959 return bodyExpression instanceof KtReturnExpression; 1960 } 1961 1962 private static boolean isLambdaVoidBody(KtElement bodyExpression, Type returnType) { 1963 if (bodyExpression instanceof KtBlockExpression) { 1964 PsiElement parent = bodyExpression.getParent(); 1965 if (parent instanceof KtFunctionLiteral) { 1966 return Type.VOID_TYPE.equals(returnType); 1967 } 1968 } 1969 1970 return false; 1971 } 1972 1973 @Override 1974 public StackValue visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, @NotNull StackValue receiver) { 1975 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext); 1976 1977 DeclarationDescriptor descriptor; 1978 if (resolvedCall == null) { 1979 descriptor = bindingContext.get(REFERENCE_TARGET, expression); 1980 } 1981 else { 1982 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1983 VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall; 1984 resolvedCall = call.getVariableCall(); 1985 } 1986 receiver = StackValue.receiver(resolvedCall, receiver, this, null); 1987 descriptor = resolvedCall.getResultingDescriptor(); 1988 if (descriptor instanceof FakeCallableDescriptorForObject) { 1989 descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor(); 1990 } 1991 } 1992 1993 assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'"; 1994 descriptor = descriptor.getOriginal(); 1995 1996 boolean isSyntheticField = descriptor instanceof SyntheticFieldDescriptor; 1997 if (isSyntheticField) { 1998 descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor(); 1999 } 2000 if (descriptor instanceof CallableMemberDescriptor) { 2001 CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor); 2002 2003 IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor); 2004 if (intrinsic instanceof IntrinsicPropertyGetter) { 2005 //TODO: intrinsic properties (see intermediateValueForProperty) 2006 Type returnType = typeMapper.mapType(memberDescriptor); 2007 StackValue intrinsicResult = ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver); 2008 if (intrinsicResult != null) return intrinsicResult; 2009 } 2010 } 2011 2012 if (descriptor instanceof PropertyDescriptor) { 2013 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 2014 2015 Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject()); 2016 if (!codegenExtensions.isEmpty() && resolvedCall != null) { 2017 ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v); 2018 KotlinType returnType = propertyDescriptor.getReturnType(); 2019 for (ExpressionCodegenExtension extension : codegenExtensions) { 2020 if (returnType != null) { 2021 StackValue value = extension.applyProperty(receiver, resolvedCall, context); 2022 if (value != null) return value; 2023 } 2024 } 2025 } 2026 2027 boolean directToField = isSyntheticField && contextKind() != OwnerKind.DEFAULT_IMPLS; 2028 ClassDescriptor superCallTarget = resolvedCall == null ? null : getSuperCallTarget(resolvedCall.getCall()); 2029 2030 if (directToField) { 2031 receiver = StackValue.receiverWithoutReceiverArgument(receiver); 2032 } 2033 2034 return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver); 2035 } 2036 2037 if (descriptor instanceof ClassDescriptor) { 2038 ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; 2039 if (isObject(classDescriptor)) { 2040 return StackValue.singleton(classDescriptor, typeMapper); 2041 } 2042 if (isEnumEntry(classDescriptor)) { 2043 return StackValue.enumEntry(classDescriptor, typeMapper); 2044 } 2045 ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor(); 2046 if (companionObjectDescriptor != null) { 2047 return StackValue.singleton(companionObjectDescriptor, typeMapper); 2048 } 2049 return StackValue.none(); 2050 } 2051 2052 StackValue localOrCaptured = findLocalOrCapturedValue(descriptor); 2053 if (localOrCaptured != null) { 2054 return localOrCaptured; 2055 } 2056 throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); 2057 } 2058 2059 @Nullable 2060 private ClassDescriptor getSuperCallTarget(@NotNull Call call) { 2061 KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call); 2062 return superExpression == null ? null : getSuperCallLabelTarget(context, superExpression); 2063 } 2064 2065 @Nullable 2066 public StackValue findLocalOrCapturedValue(@NotNull DeclarationDescriptor descriptor) { 2067 int index = lookupLocalIndex(descriptor); 2068 if (index >= 0) { 2069 return stackValueForLocal(descriptor, index); 2070 } 2071 2072 return findCapturedValue(descriptor); 2073 } 2074 2075 @Nullable 2076 public StackValue findCapturedValue(@NotNull DeclarationDescriptor descriptor) { 2077 if (context instanceof ConstructorContext) { 2078 return lookupCapturedValueInConstructorParameters(descriptor); 2079 } 2080 2081 return context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false); 2082 } 2083 2084 @Nullable 2085 private StackValue lookupCapturedValueInConstructorParameters(@NotNull DeclarationDescriptor descriptor) { 2086 StackValue parentResult = context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false); 2087 if (context.closure == null || parentResult == null) return parentResult; 2088 2089 int parameterOffsetInConstructor = context.closure.getCapturedParameterOffsetInConstructor(descriptor); 2090 // when captured parameter is singleton 2091 // see compiler/testData/codegen/box/objects/objectInLocalAnonymousObject.kt (fun local() captured in A) 2092 if (parameterOffsetInConstructor == -1) return parentResult; 2093 2094 assert parentResult instanceof StackValue.Field || parentResult instanceof StackValue.FieldForSharedVar 2095 : "Part of closure should be either Field or FieldForSharedVar"; 2096 2097 if (parentResult instanceof StackValue.FieldForSharedVar) { 2098 return StackValue.shared(parameterOffsetInConstructor, parentResult.type); 2099 } 2100 2101 return StackValue.local(parameterOffsetInConstructor, parentResult.type); 2102 } 2103 2104 private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) { 2105 if (descriptor instanceof VariableDescriptor) { 2106 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 2107 KotlinType outType = ((VariableDescriptor) descriptor).getType(); 2108 if (sharedVarType != null) { 2109 return StackValue.shared(index, asmType(outType)); 2110 } 2111 else { 2112 return StackValue.local(index, asmType(outType)); 2113 } 2114 } 2115 else { 2116 return StackValue.local(index, OBJECT_TYPE); 2117 } 2118 } 2119 2120 @Override 2121 public boolean lookupLocal(DeclarationDescriptor descriptor) { 2122 return lookupLocalIndex(descriptor) != -1; 2123 } 2124 2125 public int lookupLocalIndex(DeclarationDescriptor descriptor) { 2126 return myFrameMap.getIndex(descriptor); 2127 } 2128 2129 @Nullable 2130 private static KotlinType getPropertyDelegateType(@NotNull PropertyDescriptor descriptor, @NotNull BindingContext bindingContext) { 2131 PropertyGetterDescriptor getter = descriptor.getGetter(); 2132 if (getter != null) { 2133 Call call = bindingContext.get(DELEGATED_PROPERTY_CALL, getter); 2134 if (call != null) { 2135 assert call.getExplicitReceiver() != null : "No explicit receiver for call:" + call; 2136 return ((ReceiverValue) call.getExplicitReceiver()).getType(); 2137 } 2138 } 2139 return null; 2140 } 2141 2142 @NotNull 2143 public StackValue.Property intermediateValueForProperty( 2144 @NotNull PropertyDescriptor propertyDescriptor, 2145 boolean forceField, 2146 @Nullable ClassDescriptor superCallTarget, 2147 @NotNull StackValue receiver 2148 ) { 2149 return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver); 2150 } 2151 2152 private CodegenContext getBackingFieldContext( 2153 @NotNull FieldAccessorKind accessorKind, 2154 @NotNull DeclarationDescriptor containingDeclaration 2155 ) { 2156 switch (accessorKind) { 2157 case NORMAL: return context.getParentContext(); 2158 // For companion object property, backing field lives in object containing class 2159 // Otherwise, it lives in its containing declaration 2160 case IN_CLASS_COMPANION: return context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); 2161 case FIELD_FROM_LOCAL: return context.findParentContextWithDescriptor(containingDeclaration); 2162 default: throw new IllegalStateException(); 2163 } 2164 } 2165 2166 public StackValue.Property intermediateValueForProperty( 2167 @NotNull PropertyDescriptor propertyDescriptor, 2168 boolean forceField, 2169 boolean syntheticBackingField, 2170 @Nullable ClassDescriptor superCallTarget, 2171 boolean skipAccessorsForPrivateFieldInOuterClass, 2172 StackValue receiver 2173 ) { 2174 if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) { 2175 return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver); 2176 } 2177 2178 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 2179 2180 FieldAccessorKind fieldAccessorKind = FieldAccessorKind.NORMAL; 2181 boolean isBackingFieldInClassCompanion = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor); 2182 if (isBackingFieldInClassCompanion && (forceField || propertyDescriptor.isConst() && Visibilities.isPrivate(propertyDescriptor.getVisibility()))) { 2183 fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION; 2184 } 2185 else if (syntheticBackingField && context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration) { 2186 fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL; 2187 } 2188 boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) || 2189 AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor); 2190 boolean isSuper = superCallTarget != null; 2191 boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; 2192 2193 KotlinType delegateType = getPropertyDelegateType(propertyDescriptor, bindingContext); 2194 boolean isDelegatedProperty = delegateType != null; 2195 2196 CallableMethod callableGetter = null; 2197 CallableMethod callableSetter = null; 2198 2199 CodegenContext backingFieldContext = getBackingFieldContext(fieldAccessorKind, containingDeclaration); 2200 DeclarationDescriptor ownerDescriptor = containingDeclaration; 2201 boolean skipPropertyAccessors; 2202 2203 PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); 2204 if (fieldAccessorKind != FieldAccessorKind.NORMAL) { 2205 int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty); 2206 skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass; 2207 if (!skipPropertyAccessors) { 2208 //noinspection ConstantConditions 2209 propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor( 2210 propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget 2211 ); 2212 assert propertyDescriptor instanceof AccessorForPropertyBackingField : 2213 "Unexpected accessor descriptor: " + propertyDescriptor; 2214 ownerDescriptor = propertyDescriptor; 2215 } 2216 } 2217 else { 2218 if (!isBackingFieldInClassCompanion) { 2219 ownerDescriptor = propertyDescriptor; 2220 } 2221 skipPropertyAccessors = forceField; 2222 } 2223 2224 if (!skipPropertyAccessors) { 2225 if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) { 2226 propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget); 2227 2228 propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget); 2229 2230 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 2231 if (getter != null && !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) { 2232 callableGetter = typeMapper.mapToCallableMethod(getter, isSuper); 2233 } 2234 } 2235 2236 if (propertyDescriptor.isVar()) { 2237 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 2238 if (setter != null && 2239 !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context) && 2240 !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) { 2241 callableSetter = typeMapper.mapToCallableMethod(setter, isSuper); 2242 } 2243 } 2244 } 2245 2246 if (!isStaticBackingField) { 2247 propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); 2248 } 2249 2250 Type backingFieldOwner = typeMapper.mapOwner(ownerDescriptor); 2251 2252 String fieldName; 2253 if (isExtensionProperty && !isDelegatedProperty) { 2254 fieldName = null; 2255 } 2256 else if (originalPropertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) { 2257 assert backingFieldContext instanceof FieldOwnerContext 2258 : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext"; 2259 fieldName = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty); 2260 } 2261 else { 2262 fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty); 2263 } 2264 2265 return StackValue.property(propertyDescriptor, backingFieldOwner, 2266 typeMapper.mapType( 2267 isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), 2268 isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver); 2269 } 2270 2271 @NotNull 2272 private StackValue.Property intermediateValueForSyntheticExtensionProperty( 2273 @NotNull SyntheticJavaPropertyDescriptor propertyDescriptor, 2274 StackValue receiver 2275 ) { 2276 Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType()); 2277 CallableMethod callableGetter = 2278 typeMapper.mapToCallableMethod(context.accessibleDescriptor(propertyDescriptor.getGetMethod(), null), false); 2279 FunctionDescriptor setMethod = propertyDescriptor.getSetMethod(); 2280 CallableMethod callableSetter = 2281 setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null; 2282 return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver); 2283 } 2284 2285 @Override 2286 public StackValue visitCallExpression(@NotNull KtCallExpression expression, StackValue receiver) { 2287 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 2288 FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); 2289 2290 if (descriptor instanceof ConstructorDescriptor) { 2291 return generateNewCall(expression, resolvedCall); 2292 } 2293 2294 if (descriptor.getOriginal() instanceof SamConstructorDescriptor) { 2295 KtExpression argumentExpression = bindingContext.get(SAM_CONSTRUCTOR_TO_ARGUMENT, expression); 2296 assert argumentExpression != null : "Argument expression is not saved for a SAM constructor: " + descriptor; 2297 return genSamInterfaceValue(argumentExpression, this); 2298 } 2299 2300 return invokeFunction(resolvedCall, receiver); 2301 } 2302 2303 @Nullable 2304 private StackValue genSamInterfaceValue( 2305 @NotNull KtExpression probablyParenthesizedExpression, 2306 @NotNull final KtVisitor<StackValue, StackValue> visitor 2307 ) { 2308 final KtExpression expression = KtPsiUtil.deparenthesize(probablyParenthesizedExpression); 2309 final SamType samType = bindingContext.get(SAM_VALUE, probablyParenthesizedExpression); 2310 if (samType == null || expression == null) return null; 2311 2312 if (expression instanceof KtLambdaExpression) { 2313 return genClosure(((KtLambdaExpression) expression).getFunctionLiteral(), samType); 2314 } 2315 2316 if (expression instanceof KtNamedFunction) { 2317 return genClosure((KtNamedFunction) expression, samType); 2318 } 2319 2320 final Type asmType = 2321 state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this); 2322 2323 return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() { 2324 @Override 2325 public Unit invoke(InstructionAdapter v) { 2326 v.anew(asmType); 2327 v.dup(); 2328 2329 Type functionType = typeMapper.mapType(samType.getKotlinFunctionType()); 2330 expression.accept(visitor, StackValue.none()).put(functionType, v); 2331 2332 Label ifNonNull = new Label(); 2333 Label afterAll = new Label(); 2334 2335 v.dup(); 2336 v.ifnonnull(ifNonNull); 2337 2338 // if null: pop function value and wrapper objects, put null 2339 v.pop(); 2340 v.pop2(); 2341 v.aconst(null); 2342 v.goTo(afterAll); 2343 2344 v.mark(ifNonNull); 2345 v.invokespecial(asmType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), false); 2346 2347 v.mark(afterAll); 2348 return null; 2349 } 2350 }); 2351 } 2352 2353 @NotNull 2354 protected FunctionDescriptor accessibleFunctionDescriptor(@NotNull ResolvedCall<?> resolvedCall) { 2355 FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2356 FunctionDescriptor originalIfSamAdapter = SamCodegenUtil.getOriginalIfSamAdapter(descriptor); 2357 if (originalIfSamAdapter != null) { 2358 descriptor = originalIfSamAdapter; 2359 } 2360 // $default method is not private, so you need no accessor to call it 2361 return CallUtilKt.usesDefaultArguments(resolvedCall) 2362 ? descriptor 2363 : context.accessibleDescriptor(descriptor, getSuperCallTarget(resolvedCall.getCall())); 2364 } 2365 2366 @NotNull 2367 public StackValue invokeFunction(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) { 2368 return invokeFunction(resolvedCall.getCall(), resolvedCall, receiver); 2369 } 2370 2371 @NotNull 2372 public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) { 2373 FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall); 2374 ClassDescriptor superCallTarget = getSuperCallTarget(call); 2375 2376 fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget); 2377 2378 Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject()); 2379 if (!codegenExtensions.isEmpty()) { 2380 ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v); 2381 for (ExpressionCodegenExtension extension : codegenExtensions) { 2382 StackValue stackValue = extension.applyFunction(receiver, resolvedCall, context); 2383 if (stackValue != null) return stackValue; 2384 } 2385 } 2386 2387 Callable callable = resolveToCallable(fd, superCallTarget != null, resolvedCall); 2388 2389 return callable.invokeMethodWithArguments(resolvedCall, receiver, this); 2390 } 2391 2392 @Nullable 2393 // Find the first parent of the current context which corresponds to a subclass of a given class 2394 public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) { 2395 CodegenContext c = context; 2396 while (c != null) { 2397 if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) { 2398 return c; 2399 } 2400 c = c.getParentContext(); 2401 } 2402 return null; 2403 } 2404 2405 @NotNull 2406 Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull ResolvedCall resolvedCall) { 2407 IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd); 2408 if (intrinsic != null) { 2409 return intrinsic.toCallable(fd, superCall, resolvedCall, this); 2410 } 2411 2412 return resolveToCallableMethod(fd, superCall); 2413 } 2414 2415 @NotNull 2416 private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall) { 2417 return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall); 2418 } 2419 2420 public void invokeMethodWithArguments( 2421 @NotNull Callable callableMethod, 2422 @NotNull ResolvedCall<?> resolvedCall, 2423 @NotNull StackValue receiver 2424 ) { 2425 CallGenerator callGenerator = getOrCreateCallGenerator(resolvedCall); 2426 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 2427 2428 assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) : 2429 "Tail recursive method can't be inlined: " + descriptor; 2430 2431 ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(this, callGenerator, descriptor.getValueParameters(), 2432 callableMethod.getValueParameterTypes()); 2433 2434 invokeMethodWithArguments(callableMethod, resolvedCall, receiver, callGenerator, argumentGenerator); 2435 } 2436 2437 public void invokeMethodWithArguments( 2438 @NotNull Callable callableMethod, 2439 @NotNull ResolvedCall<?> resolvedCall, 2440 @NotNull StackValue receiver, 2441 @NotNull CallGenerator callGenerator, 2442 @NotNull ArgumentGenerator argumentGenerator 2443 ) { 2444 boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor; 2445 if (!isConstructor) { // otherwise already 2446 receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); 2447 receiver.put(receiver.type, v); 2448 callableMethod.afterReceiverGeneration(v); 2449 } 2450 2451 callGenerator.putHiddenParams(); 2452 2453 List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex(); 2454 assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor(); 2455 2456 DefaultCallArgs defaultArgs = 2457 argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values())); 2458 2459 if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { 2460 tailRecursionCodegen.generateTailRecursion(resolvedCall); 2461 return; 2462 } 2463 2464 boolean defaultMaskWasGenerated = defaultArgs.generateOnStackIfNeeded(callGenerator, isConstructor); 2465 2466 // Extra constructor marker argument 2467 if (callableMethod instanceof CallableMethod) { 2468 List<JvmMethodParameterSignature> callableParameters = ((CallableMethod) callableMethod).getValueParameters(); 2469 for (JvmMethodParameterSignature parameter: callableParameters) { 2470 if (parameter.getKind() == JvmMethodParameterKind.CONSTRUCTOR_MARKER) { 2471 callGenerator.putValueIfNeeded(parameter.getAsmType(), StackValue.constant(null, parameter.getAsmType())); 2472 } 2473 } 2474 } 2475 2476 callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this); 2477 2478 KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType(); 2479 if (returnType != null && KotlinBuiltIns.isNothing(returnType)) { 2480 v.aconst(null); 2481 v.athrow(); 2482 } 2483 } 2484 2485 @NotNull 2486 private CallGenerator getOrCreateCallGenerator( 2487 @NotNull CallableDescriptor descriptor, 2488 @Nullable KtElement callElement, 2489 @Nullable TypeParameterMappings typeParameterMappings, 2490 boolean isDefaultCompilation 2491 ) { 2492 if (callElement == null) return defaultCallGenerator; 2493 2494 // We should inline callable containing reified type parameters even if inline is disabled 2495 // because they may contain something to reify and straight call will probably fail at runtime 2496 boolean isInline = (state.isInlineEnabled() || InlineUtil.containsReifiedTypeParameters(descriptor)) && 2497 (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor)); 2498 2499 if (!isInline) return defaultCallGenerator; 2500 2501 FunctionDescriptor original = DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal()); 2502 if (isDefaultCompilation) { 2503 return new InlineCodegenForDefaultBody(original, this, state); 2504 } 2505 else { 2506 return new InlineCodegen(this, state, original, callElement, typeParameterMappings); 2507 } 2508 } 2509 2510 @NotNull 2511 protected CallGenerator getOrCreateCallGeneratorForDefaultImplBody(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) { 2512 return getOrCreateCallGenerator(descriptor, function, null, true); 2513 } 2514 2515 @NotNull 2516 CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) { 2517 Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments(); 2518 TypeParameterMappings mappings = new TypeParameterMappings(); 2519 for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) { 2520 TypeParameterDescriptor key = entry.getKey(); 2521 KotlinType type = entry.getValue(); 2522 2523 boolean isReified = key.isReified() || InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor()); 2524 2525 Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type); 2526 if (typeParameterAndReificationArgument == null) { 2527 KotlinType approximatedType = CapturedTypeApproximationKt.approximateCapturedTypes(entry.getValue()).getUpper(); 2528 // type is not generic 2529 JvmSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE); 2530 Type asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter); 2531 2532 mappings.addParameterMappingToType( 2533 key.getName().getIdentifier(), approximatedType, asmType, signatureWriter.toString(), isReified 2534 ); 2535 } 2536 else { 2537 mappings.addParameterMappingForFurtherReification( 2538 key.getName().getIdentifier(), type, typeParameterAndReificationArgument.getSecond(), isReified 2539 ); 2540 } 2541 } 2542 return getOrCreateCallGenerator( 2543 resolvedCall.getResultingDescriptor(), resolvedCall.getCall().getCallElement(), mappings, false); 2544 } 2545 2546 2547 @Nullable 2548 private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) { 2549 int arrayDepth = 0; 2550 boolean isNullable = type.isMarkedNullable(); 2551 while (KotlinBuiltIns.isArray(type)) { 2552 arrayDepth++; 2553 type = type.getArguments().get(0).getType(); 2554 } 2555 2556 TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type); 2557 if (parameterDescriptor == null) return null; 2558 2559 return new Pair<TypeParameterDescriptor, ReificationArgument>( 2560 parameterDescriptor, 2561 new ReificationArgument(parameterDescriptor.getName().asString(), isNullable, arrayDepth)); 2562 } 2563 2564 @NotNull 2565 public StackValue generateReceiverValue(@Nullable ReceiverValue receiverValue, boolean isSuper) { 2566 if (receiverValue instanceof ImplicitClassReceiver) { 2567 ClassDescriptor receiverDescriptor = ((ImplicitClassReceiver) receiverValue).getDeclarationDescriptor(); 2568 if (DescriptorUtils.isCompanionObject(receiverDescriptor)) { 2569 CallableMemberDescriptor contextDescriptor = context.getContextDescriptor(); 2570 if (contextDescriptor instanceof FunctionDescriptor && receiverDescriptor == contextDescriptor.getContainingDeclaration()) { 2571 return StackValue.LOCAL_0; 2572 } 2573 else { 2574 return StackValue.singleton(receiverDescriptor, typeMapper); 2575 } 2576 } 2577 else if (receiverDescriptor instanceof ScriptDescriptor) { 2578 return generateScriptReceiver 2579 ((ScriptDescriptor) receiverDescriptor); 2580 } 2581 else { 2582 return StackValue.thisOrOuter(this, receiverDescriptor, isSuper, 2583 receiverValue instanceof CastImplicitClassReceiver || isEnumEntry(receiverDescriptor)); 2584 } 2585 } 2586 else if (receiverValue instanceof ExtensionReceiver) { 2587 return generateReceiver(((ExtensionReceiver) receiverValue).getDeclarationDescriptor()); 2588 } 2589 else if (receiverValue instanceof ExpressionReceiver) { 2590 return gen(((ExpressionReceiver) receiverValue).getExpression()); 2591 } 2592 else { 2593 throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue); 2594 } 2595 } 2596 2597 @NotNull 2598 private StackValue generateReceiver(@NotNull CallableDescriptor descriptor) { 2599 return context.generateReceiver(descriptor, state, false); 2600 } 2601 2602 @NotNull 2603 private StackValue generateScriptReceiver(@NotNull ScriptDescriptor receiver) { 2604 CodegenContext cur = context; 2605 StackValue result = StackValue.LOCAL_0; 2606 boolean inStartConstructorContext = cur instanceof ConstructorContext; 2607 while (cur != null) { 2608 if (!inStartConstructorContext) { 2609 cur = getNotNullParentContextForMethod(cur); 2610 } 2611 2612 if (cur instanceof ScriptContext) { 2613 ScriptContext scriptContext = (ScriptContext) cur; 2614 2615 if (scriptContext.getScriptDescriptor() == receiver) { 2616 //TODO lazy 2617 return result; 2618 } 2619 Type currentScriptType = typeMapper.mapType(scriptContext.getScriptDescriptor()); 2620 Type classType = typeMapper.mapType(receiver); 2621 String fieldName = scriptContext.getScriptFieldName(receiver); 2622 return StackValue.field(classType, currentScriptType, fieldName, false, result, receiver); 2623 } 2624 2625 result = cur.getOuterExpression(result, false); 2626 2627 if (inStartConstructorContext) { 2628 cur = getNotNullParentContextForMethod(cur); 2629 inStartConstructorContext = false; 2630 } 2631 2632 cur = cur.getParentContext(); 2633 } 2634 2635 throw new UnsupportedOperationException(); 2636 } 2637 2638 @NotNull 2639 public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) { 2640 return generateThisOrOuter(calleeContainingClass, isSuper, false); 2641 } 2642 2643 @NotNull 2644 public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) { 2645 boolean isSingleton = calleeContainingClass.getKind().isSingleton(); 2646 if (isSingleton) { 2647 if (calleeContainingClass.equals(context.getThisDescriptor()) && 2648 !AnnotationUtilKt.isPlatformStaticInObjectOrClass(context.getContextDescriptor())) { 2649 return StackValue.local(0, typeMapper.mapType(calleeContainingClass)); 2650 } 2651 else if (isEnumEntry(calleeContainingClass)) { 2652 return StackValue.enumEntry(calleeContainingClass, typeMapper); 2653 } 2654 else { 2655 return StackValue.singleton(calleeContainingClass, typeMapper); 2656 } 2657 } 2658 2659 CodegenContext cur = context; 2660 Type type = asmType(calleeContainingClass.getDefaultType()); 2661 StackValue result = StackValue.local(0, type); 2662 boolean inStartConstructorContext = cur instanceof ConstructorContext; 2663 while (cur != null) { 2664 ClassDescriptor thisDescriptor = cur.getThisDescriptor(); 2665 2666 if (!isSuper && thisDescriptor == calleeContainingClass) { 2667 return result; 2668 } 2669 2670 if (!forceOuter && isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { 2671 return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass); 2672 } 2673 2674 forceOuter = false; 2675 2676 //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer 2677 if (inStartConstructorContext) { 2678 result = cur.getOuterExpression(result, false); 2679 cur = getNotNullParentContextForMethod(cur); 2680 inStartConstructorContext = false; 2681 } 2682 else { 2683 cur = getNotNullParentContextForMethod(cur); 2684 result = cur.getOuterExpression(result, false); 2685 } 2686 2687 cur = cur.getParentContext(); 2688 } 2689 2690 throw new UnsupportedOperationException(); 2691 } 2692 2693 @NotNull 2694 private static CodegenContext getNotNullParentContextForMethod(CodegenContext cur) { 2695 if (cur instanceof MethodContext) { 2696 cur = cur.getParentContext(); 2697 } 2698 assert cur != null; 2699 return cur; 2700 } 2701 2702 2703 public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) { 2704 Type type = asmType(outType); 2705 assert type.getSort() == Type.ARRAY; 2706 Type elementType = correctElementType(type); 2707 List<ValueArgument> arguments = valueArgument.getArguments(); 2708 int size = arguments.size(); 2709 2710 boolean hasSpread = false; 2711 for (int i = 0; i != size; ++i) { 2712 if (arguments.get(i).getSpreadElement() != null) { 2713 hasSpread = true; 2714 break; 2715 } 2716 } 2717 2718 if (hasSpread) { 2719 boolean arrayOfReferences = KotlinBuiltIns.isArray(outType); 2720 if (size == 1) { 2721 // Arrays.copyOf(array, newLength) 2722 ValueArgument argument = arguments.get(0); 2723 Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;") 2724 : Type.getType("[" + elementType.getDescriptor()); 2725 gen(argument.getArgumentExpression(), type); 2726 v.dup(); 2727 v.arraylength(); 2728 v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false); 2729 if (arrayOfReferences) { 2730 v.checkcast(type); 2731 } 2732 } 2733 else { 2734 String owner; 2735 String addDescriptor; 2736 String toArrayDescriptor; 2737 if (arrayOfReferences) { 2738 owner = "kotlin/jvm/internal/SpreadBuilder"; 2739 addDescriptor = "(Ljava/lang/Object;)V"; 2740 toArrayDescriptor = "([Ljava/lang/Object;)[Ljava/lang/Object;"; 2741 } 2742 else { 2743 String spreadBuilderClassName = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(elementType).getTypeName().getIdentifier() + "SpreadBuilder"; 2744 owner = "kotlin/jvm/internal/" + spreadBuilderClassName; 2745 addDescriptor = "(" + elementType.getDescriptor() + ")V"; 2746 toArrayDescriptor = "()" + type.getDescriptor(); 2747 } 2748 v.anew(Type.getObjectType(owner)); 2749 v.dup(); 2750 v.iconst(size); 2751 v.invokespecial(owner, "<init>", "(I)V", false); 2752 for (int i = 0; i != size; ++i) { 2753 v.dup(); 2754 ValueArgument argument = arguments.get(i); 2755 if (argument.getSpreadElement() != null) { 2756 gen(argument.getArgumentExpression(), OBJECT_TYPE); 2757 v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false); 2758 } 2759 else { 2760 gen(argument.getArgumentExpression(), elementType); 2761 v.invokevirtual(owner, "add", addDescriptor, false); 2762 } 2763 } 2764 if (arrayOfReferences) { 2765 v.dup(); 2766 v.invokevirtual(owner, "size", "()I", false); 2767 newArrayInstruction(outType); 2768 v.invokevirtual(owner, "toArray", toArrayDescriptor, false); 2769 v.checkcast(type); 2770 } 2771 else { 2772 v.invokevirtual(owner, "toArray", toArrayDescriptor, false); 2773 } 2774 } 2775 } 2776 else { 2777 v.iconst(arguments.size()); 2778 newArrayInstruction(outType); 2779 for (int i = 0; i != size; ++i) { 2780 v.dup(); 2781 StackValue rightSide = gen(arguments.get(i).getArgumentExpression()); 2782 StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v); 2783 } 2784 } 2785 } 2786 2787 public int indexOfLocal(KtReferenceExpression lhs) { 2788 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs); 2789 if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) { 2790 return -1; 2791 } 2792 return lookupLocalIndex(declarationDescriptor); 2793 } 2794 2795 @Override 2796 public StackValue visitClassLiteralExpression(@NotNull KtClassLiteralExpression expression, StackValue data) { 2797 KotlinType type = bindingContext.getType(expression); 2798 assert type != null; 2799 2800 assert state.getReflectionTypes().getKClass().getTypeConstructor().equals(type.getConstructor()) 2801 : "::class expression should be type checked to a KClass: " + type; 2802 2803 return generateClassLiteralReference(typeMapper, CollectionsKt.single(type.getArguments()).getType(), this); 2804 } 2805 2806 @Override 2807 public StackValue visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, StackValue data) { 2808 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext); 2809 FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); 2810 if (functionDescriptor != null) { 2811 FunctionReferenceGenerationStrategy strategy = new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); 2812 return genClosure(expression, functionDescriptor, strategy, null, (FunctionDescriptor) resolvedCall.getResultingDescriptor()); 2813 } 2814 2815 VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); 2816 if (variableDescriptor != null) { 2817 return generatePropertyReference(expression, variableDescriptor, resolvedCall); 2818 } 2819 2820 throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); 2821 } 2822 2823 @NotNull 2824 private StackValue generatePropertyReference( 2825 @NotNull KtElement element, 2826 @NotNull VariableDescriptor variableDescriptor, 2827 @NotNull ResolvedCall<?> resolvedCall 2828 ) { 2829 ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor); 2830 2831 ClassBuilder classBuilder = state.getFactory().newVisitor( 2832 JvmDeclarationOriginKt.OtherOrigin(element), 2833 typeMapper.mapClass(classDescriptor), 2834 element.getContainingFile() 2835 ); 2836 2837 PropertyReferenceCodegen codegen = new PropertyReferenceCodegen( 2838 state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION), 2839 element, classBuilder, resolvedCall 2840 ); 2841 codegen.generate(); 2842 2843 return codegen.putInstanceOnStack(); 2844 } 2845 2846 @NotNull 2847 public static StackValue generateClassLiteralReference(@NotNull KotlinTypeMapper typeMapper, @NotNull KotlinType type) { 2848 return generateClassLiteralReference(typeMapper, type, null); 2849 } 2850 2851 @NotNull 2852 private static StackValue generateClassLiteralReference(@NotNull final KotlinTypeMapper typeMapper, @NotNull final KotlinType type, @Nullable final ExpressionCodegen codegen) { 2853 return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() { 2854 @Override 2855 public Unit invoke(InstructionAdapter v) { 2856 Type classAsmType = typeMapper.mapType(type); 2857 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); 2858 if (descriptor instanceof TypeParameterDescriptor) { 2859 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor; 2860 assert typeParameterDescriptor.isReified() : 2861 "Non-reified type parameter under ::class should be rejected by type checker: " + typeParameterDescriptor; 2862 assert codegen != null : 2863 "Reference to member of reified type should be rejected by type checker " + typeParameterDescriptor; 2864 codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS); 2865 } 2866 2867 putJavaLangClassInstance(v, classAsmType); 2868 wrapJavaClassIntoKClass(v); 2869 2870 return Unit.INSTANCE; 2871 } 2872 }); 2873 } 2874 2875 @Override 2876 public StackValue visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, StackValue receiver) { 2877 StackValue receiverValue = StackValue.none(); //gen(expression.getReceiverExpression()) 2878 return genQualified(receiverValue, expression.getSelectorExpression()); 2879 } 2880 2881 private StackValue generateExpressionWithNullFallback(@NotNull KtExpression expression, @NotNull Label ifnull) { 2882 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression); 2883 assert deparenthesized != null : "Unexpected empty expression"; 2884 2885 expression = deparenthesized; 2886 Type type = expressionType(expression); 2887 2888 if (expression instanceof KtSafeQualifiedExpression && !isPrimitive(type)) { 2889 return StackValue.coercion(generateSafeQualifiedExpression((KtSafeQualifiedExpression) expression, ifnull), type); 2890 } 2891 else { 2892 return genLazy(expression, type); 2893 } 2894 } 2895 2896 private StackValue generateSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, @NotNull Label ifNull) { 2897 KtExpression receiver = expression.getReceiverExpression(); 2898 KtExpression selector = expression.getSelectorExpression(); 2899 2900 Type receiverType = expressionType(receiver); 2901 StackValue receiverValue = generateExpressionWithNullFallback(receiver, ifNull); 2902 2903 //Do not optimize for primitives cause in case of safe call extension receiver should be generated before dispatch one 2904 StackValue newReceiver = new StackValue.SafeCall(receiverType, receiverValue, isPrimitive(receiverType) ? null : ifNull); 2905 return genQualified(newReceiver, selector); 2906 } 2907 2908 @Override 2909 public StackValue visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, StackValue unused) { 2910 Label ifnull = new Label(); 2911 Type type = boxType(expressionType(expression)); 2912 2913 StackValue value = generateSafeQualifiedExpression(expression, ifnull); 2914 StackValue newReceiver = StackValue.coercion(value, type); 2915 StackValue result; 2916 2917 if (!isPrimitive(expressionType(expression.getReceiverExpression()))) { 2918 result = new StackValue.SafeFallback(type, ifnull, newReceiver); 2919 } else { 2920 result = newReceiver; 2921 } 2922 2923 return result; 2924 } 2925 2926 @Override 2927 public StackValue visitBinaryExpression(@NotNull KtBinaryExpression expression, @NotNull StackValue receiver) { 2928 KtSimpleNameExpression reference = expression.getOperationReference(); 2929 IElementType opToken = reference.getReferencedNameElementType(); 2930 if (opToken == KtTokens.EQ) { 2931 return generateAssignmentExpression(expression); 2932 } 2933 else if (KtTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { 2934 return generateAugmentedAssignment(expression); 2935 } 2936 else if (opToken == KtTokens.ANDAND) { 2937 return generateBooleanAnd(expression); 2938 } 2939 else if (opToken == KtTokens.OROR) { 2940 return generateBooleanOr(expression); 2941 } 2942 else if (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ || 2943 opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) { 2944 return generateEquals(expression.getLeft(), expression.getRight(), opToken); 2945 } 2946 else if (opToken == KtTokens.LT || opToken == KtTokens.LTEQ || 2947 opToken == KtTokens.GT || opToken == KtTokens.GTEQ) { 2948 return generateComparison(expression, receiver); 2949 } 2950 else if (opToken == KtTokens.ELVIS) { 2951 return generateElvis(expression); 2952 } 2953 else if (opToken == KtTokens.IN_KEYWORD || opToken == KtTokens.NOT_IN) { 2954 return generateIn(StackValue.expression(expressionType(expression.getLeft()), expression.getLeft(), this), 2955 expression.getRight(), reference); 2956 } 2957 else { 2958 ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext); 2959 if (compileTimeConstant != null) { 2960 return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression)); 2961 } 2962 2963 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 2964 FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2965 2966 if (descriptor instanceof ConstructorDescriptor) { 2967 return generateConstructorCall(resolvedCall, expressionType(expression)); 2968 } 2969 2970 return invokeFunction(resolvedCall, receiver); 2971 } 2972 } 2973 2974 private StackValue generateIn(final StackValue leftValue, KtExpression rangeExpression, final KtSimpleNameExpression operationReference) { 2975 final KtExpression deparenthesized = KtPsiUtil.deparenthesize(rangeExpression); 2976 2977 assert deparenthesized != null : "For with empty range expression"; 2978 2979 return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() { 2980 @Override 2981 public Unit invoke(InstructionAdapter v) { 2982 if (isIntRangeExpr(deparenthesized) && AsmUtil.isIntPrimitive(leftValue.type)) { 2983 genInIntRange(leftValue, (KtBinaryExpression) deparenthesized); 2984 } 2985 else { 2986 ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt 2987 .getResolvedCallWithAssert(operationReference, bindingContext); 2988 StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none()); 2989 result.put(result.type, v); 2990 } 2991 if (operationReference.getReferencedNameElementType() == KtTokens.NOT_IN) { 2992 genInvertBoolean(v); 2993 } 2994 return null; 2995 } 2996 }); 2997 } 2998 2999 private void genInIntRange(StackValue leftValue, KtBinaryExpression rangeExpression) { 3000 v.iconst(1); 3001 // 1 3002 leftValue.put(Type.INT_TYPE, v); 3003 // 1 l 3004 v.dup2(); 3005 // 1 l 1 l 3006 3007 //noinspection ConstantConditions 3008 gen(rangeExpression.getLeft(), Type.INT_TYPE); 3009 // 1 l 1 l r 3010 Label lok = new Label(); 3011 v.ificmpge(lok); 3012 // 1 l 1 3013 v.pop(); 3014 v.iconst(0); 3015 v.mark(lok); 3016 // 1 l c 3017 v.dupX2(); 3018 // c 1 l c 3019 v.pop(); 3020 // c 1 l 3021 3022 gen(rangeExpression.getRight(), Type.INT_TYPE); 3023 // c 1 l r 3024 Label rok = new Label(); 3025 v.ificmple(rok); 3026 // c 1 3027 v.pop(); 3028 v.iconst(0); 3029 v.mark(rok); 3030 // c c 3031 3032 v.and(Type.INT_TYPE); 3033 } 3034 3035 private StackValue generateBooleanAnd(KtBinaryExpression expression) { 3036 return StackValue.and(gen(expression.getLeft()), gen(expression.getRight())); 3037 } 3038 3039 private StackValue generateBooleanOr(KtBinaryExpression expression) { 3040 return StackValue.or(gen(expression.getLeft()), gen(expression.getRight())); 3041 } 3042 3043 private StackValue generateEquals(KtExpression left, KtExpression right, IElementType opToken) { 3044 Type leftType = expressionType(left); 3045 Type rightType = expressionType(right); 3046 3047 if (KtPsiUtil.isNullConstant(left)) { 3048 return genCmpWithNull(right, opToken); 3049 } 3050 3051 if (KtPsiUtil.isNullConstant(right)) { 3052 return genCmpWithNull(left, opToken); 3053 } 3054 3055 if (isIntZero(left, leftType) && isIntPrimitive(rightType)) { 3056 return genCmpWithZero(right, opToken); 3057 } 3058 3059 if (isIntZero(right, rightType) && isIntPrimitive(leftType)) { 3060 return genCmpWithZero(left, opToken); 3061 } 3062 3063 if (isPrimitive(leftType) != isPrimitive(rightType)) { 3064 leftType = boxType(leftType); 3065 rightType = boxType(rightType); 3066 } 3067 3068 StackValue leftValue = genLazy(left, leftType); 3069 StackValue rightValue = genLazy(right, rightType); 3070 3071 if (opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) { 3072 // TODO: always casting to the type of the left operand in case of primitives looks wrong 3073 Type operandType = isPrimitive(leftType) ? leftType : OBJECT_TYPE; 3074 return StackValue.cmp(opToken, operandType, leftValue, rightValue); 3075 } 3076 3077 return genEqualsForExpressionsOnStack(opToken, leftValue, rightValue); 3078 } 3079 3080 private boolean isIntZero(KtExpression expr, Type exprType) { 3081 ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext); 3082 return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue()); 3083 } 3084 3085 private StackValue genCmpWithZero(KtExpression exp, IElementType opToken) { 3086 return StackValue.compareIntWithZero(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNE : IFEQ); 3087 } 3088 3089 private StackValue genCmpWithNull(KtExpression exp, IElementType opToken) { 3090 return StackValue.compareWithNull(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNONNULL : IFNULL); 3091 } 3092 3093 private StackValue generateElvis(@NotNull final KtBinaryExpression expression) { 3094 KtExpression left = expression.getLeft(); 3095 3096 final Type exprType = expressionType(expression); 3097 final Type leftType = expressionType(left); 3098 3099 final Label ifNull = new Label(); 3100 3101 3102 assert left != null : "left expression in elvis should be not null: " + expression.getText(); 3103 final StackValue value = generateExpressionWithNullFallback(left, ifNull); 3104 3105 if (isPrimitive(leftType)) { 3106 return value; 3107 } 3108 3109 return StackValue.operation(exprType, new Function1<InstructionAdapter, Unit>() { 3110 @Override 3111 public Unit invoke(InstructionAdapter v) { 3112 value.put(value.type, v); 3113 v.dup(); 3114 3115 v.ifnull(ifNull); 3116 StackValue.onStack(leftType).put(exprType, v); 3117 3118 Label end = new Label(); 3119 v.goTo(end); 3120 3121 v.mark(ifNull); 3122 v.pop(); 3123 gen(expression.getRight(), exprType); 3124 v.mark(end); 3125 return null; 3126 } 3127 }); 3128 } 3129 3130 private StackValue generateComparison(KtBinaryExpression expression, StackValue receiver) { 3131 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 3132 3133 KtExpression left = expression.getLeft(); 3134 KtExpression right = expression.getRight(); 3135 3136 Type type; 3137 StackValue leftValue; 3138 StackValue rightValue; 3139 Type leftType = expressionType(left); 3140 Type rightType = expressionType(right); 3141 Callable callable = resolveToCallable((FunctionDescriptor) resolvedCall.getResultingDescriptor(), false, resolvedCall); 3142 if (isPrimitive(leftType) && isPrimitive(rightType) && callable instanceof IntrinsicCallable) { 3143 type = comparisonOperandType(leftType, rightType); 3144 leftValue = gen(left); 3145 rightValue = gen(right); 3146 } 3147 else { 3148 type = Type.INT_TYPE; 3149 leftValue = invokeFunction(resolvedCall, receiver); 3150 rightValue = StackValue.constant(0, type); 3151 } 3152 return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue); 3153 } 3154 3155 private StackValue generateAssignmentExpression(KtBinaryExpression expression) { 3156 StackValue stackValue = gen(expression.getLeft()); 3157 KtExpression right = expression.getRight(); 3158 assert right != null : expression.getText(); 3159 stackValue.store(gen(right), v); 3160 return StackValue.none(); 3161 } 3162 3163 private StackValue generateAugmentedAssignment(KtBinaryExpression expression) { 3164 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 3165 FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); 3166 Callable callable = resolveToCallable(descriptor, false, resolvedCall); 3167 KtExpression lhs = expression.getLeft(); 3168 Type lhsType = expressionType(lhs); 3169 3170 boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression)) 3171 || !KotlinBuiltIns.isUnit(descriptor.getReturnType()); 3172 3173 callAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue); 3174 3175 return StackValue.none(); 3176 } 3177 3178 private void callAugAssignMethod( 3179 @NotNull KtBinaryExpression expression, 3180 @NotNull ResolvedCall<?> resolvedCall, 3181 @NotNull Callable callable, 3182 @NotNull Type lhsType, 3183 boolean keepReturnValue 3184 ) { 3185 StackValue value = gen(expression.getLeft()); 3186 if (keepReturnValue) { 3187 value = StackValue.complexWriteReadReceiver(value); 3188 } 3189 value.put(lhsType, v); 3190 StackValue receiver = StackValue.onStack(lhsType); 3191 3192 callable.invokeMethodWithArguments(resolvedCall, receiver, this).put(callable.getReturnType(), v); 3193 3194 if (keepReturnValue) { 3195 value.store(StackValue.onStack(callable.getReturnType()), v, true); 3196 } 3197 } 3198 3199 public void invokeAppend(KtExpression expr) { 3200 ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext); 3201 3202 if (compileTimeConstant == null && expr instanceof KtBinaryExpression) { 3203 KtBinaryExpression binaryExpression = (KtBinaryExpression) expr; 3204 if (binaryExpression.getOperationToken() == KtTokens.PLUS) { 3205 KtExpression left = binaryExpression.getLeft(); 3206 KtExpression right = binaryExpression.getRight(); 3207 Type leftType = expressionType(left); 3208 3209 if (leftType.equals(JAVA_STRING_TYPE)) { 3210 invokeAppend(left); 3211 invokeAppend(right); 3212 return; 3213 } 3214 } 3215 } 3216 3217 Type exprType = expressionType(expr); 3218 if (compileTimeConstant != null) { 3219 StackValue.constant(compileTimeConstant.getValue(), exprType).put(exprType, v); 3220 } else { 3221 gen(expr, exprType); 3222 } 3223 genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType); 3224 } 3225 3226 @Nullable 3227 private static KtSimpleNameExpression targetLabel(KtExpression expression) { 3228 if (expression.getParent() instanceof KtLabeledExpression) { 3229 return ((KtLabeledExpression) expression.getParent()).getTargetLabel(); 3230 } 3231 return null; 3232 } 3233 3234 @Override 3235 public StackValue visitLabeledExpression( 3236 @NotNull KtLabeledExpression expression, StackValue receiver 3237 ) { 3238 return genQualified(receiver, expression.getBaseExpression()); 3239 } 3240 3241 @Override 3242 public StackValue visitPrefixExpression(@NotNull KtPrefixExpression expression, @NotNull StackValue receiver) { 3243 ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext); 3244 if (compileTimeConstant != null) { 3245 return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression)); 3246 } 3247 3248 DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference()); 3249 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 3250 CallableDescriptor op = resolvedCall.getResultingDescriptor(); 3251 3252 assert op instanceof FunctionDescriptor || originalOperation == null : String.valueOf(op); 3253 String operationName = originalOperation == null ? "" : originalOperation.getName().asString(); 3254 if (!(operationName.equals("inc") || operationName.equals("dec"))) { 3255 return invokeFunction(resolvedCall, receiver); 3256 } 3257 3258 int increment = operationName.equals("inc") ? 1 : -1; 3259 Type type = expressionType(expression.getBaseExpression()); 3260 StackValue value = gen(expression.getBaseExpression()); 3261 return StackValue.preIncrement(type, value, increment, resolvedCall, this); 3262 } 3263 3264 @Override 3265 public StackValue visitPostfixExpression(@NotNull final KtPostfixExpression expression, StackValue receiver) { 3266 if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL) { 3267 final StackValue base = genQualified(receiver, expression.getBaseExpression()); 3268 if (isPrimitive(base.type)) { 3269 return base; 3270 } else { 3271 return StackValue.operation(base.type, new Function1<InstructionAdapter, Unit>() { 3272 @Override 3273 public Unit invoke(InstructionAdapter v) { 3274 base.put(base.type, v); 3275 v.dup(); 3276 Label ok = new Label(); 3277 v.ifnonnull(ok); 3278 v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false); 3279 v.mark(ok); 3280 return null; 3281 } 3282 }); 3283 } 3284 } 3285 3286 DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference()); 3287 String originalOperationName = originalOperation != null ? originalOperation.getName().asString() : null; 3288 final ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); 3289 DeclarationDescriptor op = resolvedCall.getResultingDescriptor(); 3290 if (!(op instanceof FunctionDescriptor) || originalOperation == null) { 3291 throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + originalOperationName + " " + op); 3292 } 3293 3294 3295 final Type asmResultType = expressionType(expression); 3296 final Type asmBaseType = expressionType(expression.getBaseExpression()); 3297 3298 DeclarationDescriptor cls = op.getContainingDeclaration(); 3299 3300 final int increment; 3301 if (originalOperationName.equals("inc")) { 3302 increment = 1; 3303 } 3304 else if (originalOperationName.equals("dec")) { 3305 increment = -1; 3306 } 3307 else { 3308 throw new UnsupportedOperationException("Unsupported postfix operation: " + originalOperationName + " " + op); 3309 } 3310 3311 final boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls); 3312 if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) { 3313 KtExpression operand = expression.getBaseExpression(); 3314 // Optimization for j = i++, when j and i are Int without any smart cast: we just work with primitive int 3315 if (operand instanceof KtReferenceExpression && asmResultType == Type.INT_TYPE && 3316 bindingContext.get(BindingContext.SMARTCAST, operand) == null) { 3317 int index = indexOfLocal((KtReferenceExpression) operand); 3318 if (index >= 0) { 3319 return StackValue.postIncrement(index, increment); 3320 } 3321 } 3322 } 3323 3324 return StackValue.operation(asmBaseType, new Function1<InstructionAdapter, Unit>() { 3325 @Override 3326 public Unit invoke(InstructionAdapter v) { 3327 StackValue value = StackValue.complexWriteReadReceiver(gen(expression.getBaseExpression())); 3328 3329 value.put(asmBaseType, v); 3330 AsmUtil.dup(v, asmBaseType); 3331 3332 StackValue previousValue = StackValue.local(myFrameMap.enterTemp(asmBaseType), asmBaseType); 3333 previousValue.store(StackValue.onStack(asmBaseType), v); 3334 3335 Type storeType; 3336 if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) { 3337 genIncrement(asmResultType, asmBaseType, increment, v); 3338 storeType = asmBaseType; 3339 } 3340 else { 3341 StackValue result = invokeFunction(resolvedCall, StackValue.onStack(asmBaseType)); 3342 result.put(result.type, v); 3343 storeType = result.type; 3344 } 3345 3346 value.store(StackValue.onStack(storeType), v, true); 3347 3348 previousValue.put(asmBaseType, v); 3349 3350 myFrameMap.leaveTemp(asmBaseType); 3351 3352 return Unit.INSTANCE; 3353 } 3354 }); 3355 } 3356 3357 @Override 3358 public StackValue visitProperty(@NotNull KtProperty property, StackValue receiver) { 3359 KtExpression initializer = property.getInitializer(); 3360 if (initializer == null) { 3361 return StackValue.none(); 3362 } 3363 initializeLocalVariable(property, gen(initializer)); 3364 return StackValue.none(); 3365 } 3366 3367 @Override 3368 public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) { 3369 KtExpression initializer = multiDeclaration.getInitializer(); 3370 if (initializer == null) return StackValue.none(); 3371 3372 KotlinType initializerType = bindingContext.getType(initializer); 3373 assert initializerType != null; 3374 3375 Type initializerAsmType = asmType(initializerType); 3376 3377 TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType); 3378 3379 int tempVarIndex = myFrameMap.enterTemp(initializerAsmType); 3380 3381 gen(initializer, initializerAsmType); 3382 v.store(tempVarIndex, initializerAsmType); 3383 StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType); 3384 3385 for (KtDestructuringDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) { 3386 ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration); 3387 assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); 3388 Call call = makeFakeCall(initializerAsReceiver); 3389 initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, local)); 3390 } 3391 3392 if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) { 3393 v.aconst(null); 3394 v.store(tempVarIndex, initializerAsmType); 3395 } 3396 myFrameMap.leaveTemp(initializerAsmType); 3397 3398 return StackValue.none(); 3399 } 3400 3401 private void initializeLocalVariable( 3402 @NotNull KtVariableDeclaration variableDeclaration, 3403 @NotNull StackValue initializer 3404 ) { 3405 VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration); 3406 3407 if (KtPsiUtil.isScriptDeclaration(variableDeclaration)) { 3408 return; 3409 } 3410 int index = lookupLocalIndex(variableDescriptor); 3411 3412 if (index < 0) { 3413 throw new IllegalStateException("Local variable not found for " + variableDescriptor); 3414 } 3415 3416 Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); 3417 assert variableDescriptor != null; 3418 3419 Type varType = asmType(variableDescriptor.getType()); 3420 3421 StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType); 3422 3423 storeTo.putReceiver(v, false); 3424 initializer.put(initializer.type, v); 3425 3426 markLineNumber(variableDeclaration, false); 3427 3428 storeTo.storeSelector(initializer.type, v); 3429 } 3430 3431 @NotNull 3432 private StackValue generateNewCall(@NotNull KtCallExpression expression, @NotNull ResolvedCall<?> resolvedCall) { 3433 Type type = expressionType(expression); 3434 if (type.getSort() == Type.ARRAY) { 3435 //noinspection ConstantConditions 3436 return generateNewArray(expression, bindingContext.getType(expression), resolvedCall); 3437 } 3438 3439 return generateConstructorCall(resolvedCall, type); 3440 } 3441 3442 @NotNull 3443 public ConstructorDescriptor getConstructorDescriptor(@NotNull ResolvedCall<?> resolvedCall) { 3444 FunctionDescriptor accessibleDescriptor = accessibleFunctionDescriptor(resolvedCall); 3445 assert accessibleDescriptor instanceof ConstructorDescriptor : 3446 "getConstructorDescriptor must be called only for constructors: " + accessibleDescriptor; 3447 return (ConstructorDescriptor) accessibleDescriptor; 3448 } 3449 3450 @NotNull 3451 public StackValue generateConstructorCall(@NotNull final ResolvedCall<?> resolvedCall, @NotNull final Type objectType) { 3452 return StackValue.functionCall(objectType, new Function1<InstructionAdapter, Unit>() { 3453 @Override 3454 public Unit invoke(InstructionAdapter v) { 3455 v.anew(objectType); 3456 v.dup(); 3457 3458 ConstructorDescriptor constructor = getConstructorDescriptor(resolvedCall); 3459 3460 ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter(); 3461 ClassDescriptor containingDeclaration = constructor.getContainingDeclaration(); 3462 if (dispatchReceiver != null) { 3463 Type receiverType = typeMapper.mapType(dispatchReceiver.getType()); 3464 ReceiverValue receiver = resolvedCall.getDispatchReceiver(); 3465 boolean callSuper = containingDeclaration.isInner() && receiver instanceof ImplicitClassReceiver; 3466 generateReceiverValue(receiver, callSuper).put(receiverType, v); 3467 } 3468 3469 // Resolved call to local class constructor doesn't have dispatchReceiver, so we need to generate closure on stack 3470 // See StackValue.receiver for more info 3471 pushClosureOnStack(containingDeclaration, dispatchReceiver == null, defaultCallGenerator); 3472 3473 constructor = SamCodegenUtil.resolveSamAdapter(constructor); 3474 CallableMethod method = typeMapper.mapToCallableMethod(constructor, false); 3475 invokeMethodWithArguments(method, resolvedCall, StackValue.none()); 3476 3477 return Unit.INSTANCE; 3478 } 3479 }); 3480 } 3481 3482 public StackValue generateNewArray( 3483 @NotNull KtCallExpression expression, @NotNull final KotlinType arrayType, @NotNull ResolvedCall<?> resolvedCall 3484 ) { 3485 List<KtValueArgument> args = expression.getValueArguments(); 3486 assert args.size() == 1 || args.size() == 2 : "Unknown constructor called: " + args.size() + " arguments"; 3487 3488 if (args.size() == 1) { 3489 final KtExpression sizeExpression = args.get(0).getArgumentExpression(); 3490 return StackValue.operation(typeMapper.mapType(arrayType), new Function1<InstructionAdapter, Unit>() { 3491 @Override 3492 public Unit invoke(InstructionAdapter v) { 3493 gen(sizeExpression, Type.INT_TYPE); 3494 newArrayInstruction(arrayType); 3495 return Unit.INSTANCE; 3496 } 3497 }); 3498 } 3499 3500 return invokeFunction(resolvedCall, StackValue.none()); 3501 } 3502 3503 public void newArrayInstruction(@NotNull KotlinType arrayType) { 3504 if (KotlinBuiltIns.isArray(arrayType)) { 3505 KotlinType elementJetType = arrayType.getArguments().get(0).getType(); 3506 putReifiedOperationMarkerIfTypeIsReifiedParameter( 3507 elementJetType, 3508 ReifiedTypeInliner.OperationKind.NEW_ARRAY 3509 ); 3510 v.newarray(boxType(asmType(elementJetType))); 3511 } 3512 else { 3513 Type type = typeMapper.mapType(arrayType); 3514 v.newarray(correctElementType(type)); 3515 } 3516 } 3517 3518 @Override 3519 public StackValue visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression, StackValue receiver) { 3520 KtExpression array = expression.getArrayExpression(); 3521 KotlinType type = array != null ? bindingContext.getType(array) : null; 3522 Type arrayType = expressionType(array); 3523 List<KtExpression> indices = expression.getIndexExpressions(); 3524 FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression); 3525 assert operationDescriptor != null; 3526 if (arrayType.getSort() == Type.ARRAY && 3527 indices.size() == 1 && 3528 isInt(operationDescriptor.getValueParameters().get(0).getType())) { 3529 assert type != null; 3530 Type elementType; 3531 if (KotlinBuiltIns.isArray(type)) { 3532 KotlinType jetElementType = type.getArguments().get(0).getType(); 3533 elementType = boxType(asmType(jetElementType)); 3534 } 3535 else { 3536 elementType = correctElementType(arrayType); 3537 } 3538 StackValue arrayValue = genLazy(array, arrayType); 3539 StackValue index = genLazy(indices.get(0), Type.INT_TYPE); 3540 3541 return StackValue.arrayElement(elementType, arrayValue, index); 3542 } 3543 else { 3544 ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression); 3545 ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression); 3546 3547 boolean isGetter = "get".equals(operationDescriptor.getName().asString()); 3548 3549 Callable callable = resolveToCallable(operationDescriptor, false, isGetter ? resolvedGetCall : resolvedSetCall); 3550 Callable callableMethod = resolveToCallableMethod(operationDescriptor, false); 3551 Type[] argumentTypes = callableMethod.getParameterTypes(); 3552 3553 StackValue.CollectionElementReceiver collectionElementReceiver = createCollectionElementReceiver( 3554 expression, receiver, operationDescriptor, isGetter, resolvedGetCall, resolvedSetCall, callable 3555 ); 3556 3557 Type elementType = isGetter ? callableMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes); 3558 return StackValue.collectionElement(collectionElementReceiver, elementType, resolvedGetCall, resolvedSetCall, this); 3559 } 3560 } 3561 3562 @NotNull 3563 private StackValue.CollectionElementReceiver createCollectionElementReceiver( 3564 @NotNull KtArrayAccessExpression expression, 3565 @NotNull StackValue receiver, 3566 @NotNull FunctionDescriptor operationDescriptor, 3567 boolean isGetter, 3568 ResolvedCall<FunctionDescriptor> resolvedGetCall, 3569 ResolvedCall<FunctionDescriptor> resolvedSetCall, 3570 @NotNull Callable callable 3571 ) { 3572 ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall; 3573 assert resolvedCall != null : "couldn't find resolved call: " + expression.getText(); 3574 3575 List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex(); 3576 assert valueArguments != null : "Failed to arrange value arguments by index: " + operationDescriptor; 3577 3578 if (!isGetter) { 3579 assert valueArguments.size() >= 2 : "Setter call should have at least 2 arguments: " + operationDescriptor; 3580 // Skip generation of the right hand side of an indexed assignment, which is the last value argument 3581 valueArguments.remove(valueArguments.size() - 1); 3582 } 3583 3584 return new StackValue.CollectionElementReceiver( 3585 callable, receiver, resolvedGetCall, resolvedSetCall, isGetter, this, valueArguments 3586 ); 3587 } 3588 3589 @Override 3590 public StackValue visitThrowExpression(@NotNull final KtThrowExpression expression, StackValue receiver) { 3591 return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() { 3592 @Override 3593 public Unit invoke(InstructionAdapter adapter) { 3594 gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE); 3595 v.athrow(); 3596 return Unit.INSTANCE; 3597 } 3598 }); 3599 } 3600 3601 @Override 3602 public StackValue visitThisExpression(@NotNull KtThisExpression expression, StackValue receiver) { 3603 DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference()); 3604 if (descriptor instanceof ClassDescriptor) { 3605 //TODO rewrite with context.lookupInContext() 3606 return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true); 3607 } 3608 if (descriptor instanceof CallableDescriptor) { 3609 return generateReceiver((CallableDescriptor) descriptor); 3610 } 3611 throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor); 3612 } 3613 3614 @Override 3615 public StackValue visitTryExpression(@NotNull KtTryExpression expression, StackValue receiver) { 3616 return generateTryExpression(expression, false); 3617 } 3618 3619 public StackValue generateTryExpression(final KtTryExpression expression, final boolean isStatement) { 3620 /* 3621 The "returned" value of try expression with no finally is either the last expression in the try block or the last expression in the catch block 3622 (or blocks). 3623 */ 3624 3625 KotlinType jetType = bindingContext.getType(expression); 3626 assert jetType != null; 3627 final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType); 3628 3629 return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() { 3630 @Override 3631 public Unit invoke(InstructionAdapter v) { 3632 KtFinallySection finallyBlock = expression.getFinallyBlock(); 3633 FinallyBlockStackElement finallyBlockStackElement = null; 3634 if (finallyBlock != null) { 3635 finallyBlockStackElement = new FinallyBlockStackElement(expression); 3636 blockStackElements.push(finallyBlockStackElement); 3637 } 3638 3639 //PseudoInsnsPackage.saveStackBeforeTryExpr(v); 3640 3641 Label tryStart = new Label(); 3642 v.mark(tryStart); 3643 v.nop(); // prevent verify error on empty try 3644 3645 gen(expression.getTryBlock(), expectedAsmType); 3646 3647 int savedValue = -1; 3648 if (!isStatement) { 3649 savedValue = myFrameMap.enterTemp(expectedAsmType); 3650 v.store(savedValue, expectedAsmType); 3651 } 3652 3653 Label tryEnd = new Label(); 3654 v.mark(tryEnd); 3655 3656 //do it before finally block generation 3657 List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd); 3658 3659 Label end = new Label(); 3660 3661 genFinallyBlockOrGoto(finallyBlockStackElement, end, null); 3662 3663 List<KtCatchClause> clauses = expression.getCatchClauses(); 3664 for (int i = 0, size = clauses.size(); i < size; i++) { 3665 KtCatchClause clause = clauses.get(i); 3666 3667 Label clauseStart = new Label(); 3668 v.mark(clauseStart); 3669 3670 KtExpression catchBody = clause.getCatchBody(); 3671 if (catchBody != null) { 3672 markLineNumber(catchBody, false); 3673 } 3674 3675 VariableDescriptor descriptor = bindingContext.get(VALUE_PARAMETER, clause.getCatchParameter()); 3676 assert descriptor != null; 3677 Type descriptorType = asmType(descriptor.getType()); 3678 myFrameMap.enter(descriptor, descriptorType); 3679 int index = lookupLocalIndex(descriptor); 3680 v.store(index, descriptorType); 3681 3682 gen(catchBody, expectedAsmType); 3683 3684 if (!isStatement) { 3685 v.store(savedValue, expectedAsmType); 3686 } 3687 3688 myFrameMap.leave(descriptor); 3689 3690 Label clauseEnd = new Label(); 3691 v.mark(clauseEnd); 3692 3693 v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd, 3694 index); 3695 3696 genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null, null); 3697 3698 generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName()); 3699 } 3700 3701 3702 //for default catch clause 3703 if (finallyBlock != null) { 3704 Label defaultCatchStart = new Label(); 3705 v.mark(defaultCatchStart); 3706 int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE); 3707 v.store(savedException, JAVA_THROWABLE_TYPE); 3708 3709 Label defaultCatchEnd = new Label(); 3710 v.mark(defaultCatchEnd); 3711 3712 //do it before finally block generation 3713 //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter 3714 List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd); 3715 3716 3717 genFinallyBlockOrGoto(finallyBlockStackElement, null, null); 3718 3719 v.load(savedException, JAVA_THROWABLE_TYPE); 3720 myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE); 3721 3722 v.athrow(); 3723 3724 generateExceptionTable(defaultCatchStart, defaultCatchRegions, null); 3725 } 3726 3727 markLineNumber(expression, isStatement); 3728 v.mark(end); 3729 3730 if (!isStatement) { 3731 v.load(savedValue, expectedAsmType); 3732 myFrameMap.leaveTemp(expectedAsmType); 3733 } 3734 3735 if (finallyBlock != null) { 3736 blockStackElements.pop(); 3737 } 3738 return Unit.INSTANCE; 3739 } 3740 }); 3741 } 3742 3743 private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) { 3744 for (int i = 0; i < catchedRegions.size(); i += 2) { 3745 Label startRegion = catchedRegions.get(i); 3746 Label endRegion = catchedRegions.get(i+1); 3747 v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception); 3748 } 3749 } 3750 3751 @NotNull 3752 private static List<Label> getCurrentCatchIntervals( 3753 @Nullable FinallyBlockStackElement finallyBlockStackElement, 3754 @NotNull Label blockStart, 3755 @NotNull Label blockEnd 3756 ) { 3757 List<Label> gapsInBlock = 3758 finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList(); 3759 assert gapsInBlock.size() % 2 == 0; 3760 List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2); 3761 blockRegions.add(blockStart); 3762 blockRegions.addAll(gapsInBlock); 3763 blockRegions.add(blockEnd); 3764 return blockRegions; 3765 } 3766 3767 @Override 3768 public StackValue visitBinaryWithTypeRHSExpression(@NotNull KtBinaryExpressionWithTypeRHS expression, StackValue receiver) { 3769 KtExpression left = expression.getLeft(); 3770 final IElementType opToken = expression.getOperationReference().getReferencedNameElementType(); 3771 3772 final KotlinType rightType = bindingContext.get(TYPE, expression.getRight()); 3773 assert rightType != null; 3774 3775 final StackValue value = genQualified(receiver, left); 3776 3777 return StackValue.operation(boxType(asmType(rightType)), new Function1<InstructionAdapter, Unit>() { 3778 @Override 3779 public Unit invoke(InstructionAdapter v) { 3780 value.put(boxType(value.type), v); 3781 3782 if (value.type == Type.VOID_TYPE) { 3783 StackValue.putUnitInstance(v); 3784 } 3785 3786 boolean safeAs = opToken == KtTokens.AS_SAFE; 3787 Type type = boxType(asmType(rightType)); 3788 if (TypeUtils.isReifiedTypeParameter(rightType)) { 3789 putReifiedOperationMarkerIfTypeIsReifiedParameter(rightType, 3790 safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS 3791 : ReifiedTypeInliner.OperationKind.AS); 3792 v.checkcast(type); 3793 return Unit.INSTANCE; 3794 } 3795 3796 CodegenUtilKt.generateAsCast(v, rightType, type, safeAs); 3797 3798 return Unit.INSTANCE; 3799 } 3800 }); 3801 } 3802 3803 @Override 3804 public StackValue visitIsExpression(@NotNull KtIsExpression expression, StackValue receiver) { 3805 StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this); 3806 return generateIsCheck(match, expression.getTypeReference(), expression.isNegated()); 3807 } 3808 3809 private StackValue generateExpressionMatch(StackValue expressionToMatch, KtExpression patternExpression) { 3810 if (expressionToMatch != null) { 3811 Type subjectType = expressionToMatch.type; 3812 markStartLineNumber(patternExpression); 3813 KotlinType condJetType = bindingContext.getType(patternExpression); 3814 Type condType; 3815 if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) { 3816 assert condJetType != null; 3817 condType = asmType(condJetType); 3818 if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) { 3819 subjectType = boxType(subjectType); 3820 } 3821 } 3822 else { 3823 condType = OBJECT_TYPE; 3824 } 3825 StackValue condition = genLazy(patternExpression, condType); 3826 return genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.coercion(expressionToMatch, subjectType), condition); 3827 } 3828 else { 3829 return gen(patternExpression); 3830 } 3831 } 3832 3833 private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) { 3834 KotlinType jetType = bindingContext.get(TYPE, typeReference); 3835 markStartLineNumber(typeReference); 3836 StackValue value = generateIsCheck(expressionToMatch, jetType, false); 3837 return negated ? StackValue.not(value) : value; 3838 } 3839 3840 private StackValue generateIsCheck(final StackValue expressionToGen, final KotlinType kotlinType, final boolean leaveExpressionOnStack) { 3841 return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() { 3842 @Override 3843 public Unit invoke(InstructionAdapter v) { 3844 expressionToGen.put(OBJECT_TYPE, v); 3845 if (leaveExpressionOnStack) { 3846 v.dup(); 3847 } 3848 3849 Type type = boxType(asmType(kotlinType)); 3850 if (TypeUtils.isReifiedTypeParameter(kotlinType)) { 3851 putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS); 3852 v.instanceOf(type); 3853 return null; 3854 } 3855 3856 CodegenUtilKt.generateIsCheck(v, kotlinType, type); 3857 return null; 3858 } 3859 }); 3860 } 3861 3862 public void putReifiedOperationMarkerIfTypeIsReifiedParameter( 3863 @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind 3864 ) { 3865 Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type); 3866 if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) { 3867 TypeParameterDescriptor typeParameterDescriptor = typeParameterAndReificationArgument.getFirst(); 3868 if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) { 3869 parentCodegen.getReifiedTypeParametersUsages(). 3870 addUsedReifiedParameter(typeParameterDescriptor.getName().asString()); 3871 } 3872 v.iconst(operationKind.getId()); 3873 v.visitLdcInsn(typeParameterAndReificationArgument.getSecond().asString()); 3874 v.invokestatic( 3875 IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.REIFIED_OPERATION_MARKER_METHOD_NAME, 3876 Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class)), false 3877 ); 3878 } 3879 } 3880 3881 public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) { 3882 parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context); 3883 } 3884 3885 @Override 3886 public StackValue visitWhenExpression(@NotNull KtWhenExpression expression, StackValue receiver) { 3887 return generateWhenExpression(expression, false); 3888 } 3889 3890 public StackValue generateWhenExpression(final KtWhenExpression expression, final boolean isStatement) { 3891 final KtExpression expr = expression.getSubjectExpression(); 3892 final Type subjectType = expressionType(expr); 3893 3894 final Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression); 3895 3896 return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() { 3897 @Override 3898 public Unit invoke(InstructionAdapter v) { 3899 SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible( 3900 expression, isStatement, isExhaustive(expression, isStatement), ExpressionCodegen.this 3901 ); 3902 if (switchCodegen != null) { 3903 switchCodegen.generate(); 3904 return Unit.INSTANCE; 3905 } 3906 3907 int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1; 3908 if (subjectLocal != -1) { 3909 gen(expr, subjectType); 3910 tempVariables.put(expr, StackValue.local(subjectLocal, subjectType)); 3911 v.store(subjectLocal, subjectType); 3912 } 3913 3914 Label end = new Label(); 3915 boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression); 3916 3917 Label nextCondition = null; 3918 for (KtWhenEntry whenEntry : expression.getEntries()) { 3919 if (nextCondition != null) { 3920 v.mark(nextCondition); 3921 } 3922 nextCondition = new Label(); 3923 FrameMap.Mark mark = myFrameMap.mark(); 3924 Label thisEntry = new Label(); 3925 if (!whenEntry.isElse()) { 3926 KtWhenCondition[] conditions = whenEntry.getConditions(); 3927 for (int i = 0; i < conditions.length; i++) { 3928 StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]); 3929 BranchedValue.Companion.condJump(conditionValue, nextCondition, true, v); 3930 if (i < conditions.length - 1) { 3931 v.goTo(thisEntry); 3932 v.mark(nextCondition); 3933 nextCondition = new Label(); 3934 } 3935 } 3936 } 3937 3938 v.visitLabel(thisEntry); 3939 gen(whenEntry.getExpression(), resultType); 3940 mark.dropTo(); 3941 if (!whenEntry.isElse()) { 3942 v.goTo(end); 3943 } 3944 } 3945 if (!hasElse && nextCondition != null) { 3946 v.mark(nextCondition); 3947 putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement); 3948 } 3949 3950 markLineNumber(expression, isStatement); 3951 v.mark(end); 3952 3953 myFrameMap.leaveTemp(subjectType); 3954 tempVariables.remove(expr); 3955 return null; 3956 } 3957 }); 3958 } 3959 3960 private boolean isExhaustive(@NotNull KtWhenExpression whenExpression, boolean isStatement) { 3961 if (isStatement) { 3962 return Boolean.TRUE.equals(bindingContext.get(BindingContext.IMPLICIT_EXHAUSTIVE_WHEN, whenExpression)); 3963 } 3964 else { 3965 return Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, whenExpression)); 3966 } 3967 } 3968 3969 public void putUnitInstanceOntoStackForNonExhaustiveWhen( 3970 @NotNull KtWhenExpression whenExpression, 3971 boolean isStatement 3972 ) { 3973 if (isExhaustive(whenExpression, isStatement)) { 3974 // when() is supposed to be exhaustive 3975 genThrow(v, "kotlin/NoWhenBranchMatchedException", null); 3976 } 3977 else if (!isStatement) { 3978 // non-exhaustive when() with no else -> Unit must be expected 3979 StackValue.putUnitInstance(v); 3980 } 3981 } 3982 3983 private StackValue generateWhenCondition(Type subjectType, int subjectLocal, KtWhenCondition condition) { 3984 if (condition instanceof KtWhenConditionInRange) { 3985 KtWhenConditionInRange conditionInRange = (KtWhenConditionInRange) condition; 3986 return generateIn(StackValue.local(subjectLocal, subjectType), 3987 conditionInRange.getRangeExpression(), 3988 conditionInRange.getOperationReference()); 3989 } 3990 StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType); 3991 if (condition instanceof KtWhenConditionIsPattern) { 3992 KtWhenConditionIsPattern patternCondition = (KtWhenConditionIsPattern) condition; 3993 return generateIsCheck(match, patternCondition.getTypeReference(), patternCondition.isNegated()); 3994 } 3995 else if (condition instanceof KtWhenConditionWithExpression) { 3996 KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression(); 3997 return generateExpressionMatch(match, patternExpression); 3998 } 3999 else { 4000 throw new UnsupportedOperationException("unsupported kind of when condition"); 4001 } 4002 } 4003 4004 private boolean isIntRangeExpr(KtExpression rangeExpression) { 4005 if (rangeExpression instanceof KtBinaryExpression) { 4006 KtBinaryExpression binaryExpression = (KtBinaryExpression) rangeExpression; 4007 if (binaryExpression.getOperationReference().getReferencedNameElementType() == KtTokens.RANGE) { 4008 KotlinType jetType = bindingContext.getType(rangeExpression); 4009 assert jetType != null; 4010 DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); 4011 return DescriptorUtilsKt.getBuiltIns(descriptor).getIntegralRanges().contains(descriptor); 4012 } 4013 } 4014 return false; 4015 } 4016 4017 private Call makeFakeCall(ReceiverValue initializerAsReceiver) { 4018 KtSimpleNameExpression fake = KtPsiFactoryKt.KtPsiFactory(state.getProject()).createSimpleName("fake"); 4019 return CallMaker.makeCall(fake, initializerAsReceiver); 4020 } 4021 4022 @Override 4023 public String toString() { 4024 return context.getContextDescriptor().toString(); 4025 } 4026 4027 @NotNull 4028 public FrameMap getFrameMap() { 4029 return myFrameMap; 4030 } 4031 4032 @NotNull 4033 public MethodContext getContext() { 4034 return context; 4035 } 4036 4037 @NotNull 4038 public NameGenerator getInlineNameGenerator() { 4039 NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator(); 4040 Name name = context.getContextDescriptor().getName(); 4041 return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" ); 4042 } 4043 4044 public Type getReturnType() { 4045 return returnType; 4046 } 4047 4048 public Stack<BlockStackElement> getBlockStackElements() { 4049 return new Stack<BlockStackElement>(blockStackElements); 4050 } 4051 4052 public void addBlockStackElementsForNonLocalReturns(@NotNull Stack<BlockStackElement> elements, int finallyDepth) { 4053 blockStackElements.addAll(elements); 4054 this.finallyDepth = finallyDepth; 4055 } 4056 4057 private static class NonLocalReturnInfo { 4058 4059 final Type returnType; 4060 4061 final String labelName; 4062 4063 private NonLocalReturnInfo(Type type, String name) { 4064 returnType = type; 4065 labelName = name; 4066 } 4067 } 4068 }