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