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