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