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 1794 JetType delegateType = getPropertyDelegateType(propertyDescriptor, bindingContext); 1795 boolean isDelegatedProperty = delegateType != null; 1796 1797 CallableMethod callableGetter = null; 1798 CallableMethod callableSetter = null; 1799 1800 boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass; 1801 1802 CodegenContext backingFieldContext = context.getParentContext(); 1803 1804 if (isBackingFieldInAnotherClass && forceField) { 1805 //delegate call to classObject owner : OWNER 1806 backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); 1807 int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty); 1808 skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER; 1809 if (!skipPropertyAccessors) { 1810 propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType); 1811 } 1812 isStatic = true; 1813 } 1814 1815 if (!skipPropertyAccessors) { 1816 if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty, context)) { 1817 callableGetter = null; 1818 } 1819 else { 1820 if (isSuper && !isInterface(containingDeclaration)) { 1821 ClassDescriptor owner = getSuperCallLabelTarget(superExpression); 1822 CodegenContext c = context.findParentContextWithDescriptor(owner); 1823 assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor; 1824 if (c != context.getParentContext()) { 1825 propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor); 1826 } 1827 } 1828 1829 propertyDescriptor = accessiblePropertyDescriptor(propertyDescriptor); 1830 1831 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 1832 if (getter != null) { 1833 callableGetter = typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context); 1834 } 1835 } 1836 1837 if (propertyDescriptor.isVar()) { 1838 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 1839 if (setter != null) { 1840 if (couldUseDirectAccessToProperty(propertyDescriptor, false, isInsideClass, isDelegatedProperty, context)) { 1841 callableSetter = null; 1842 } 1843 else { 1844 callableSetter = typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context); 1845 } 1846 } 1847 } 1848 } 1849 1850 Type owner; 1851 CallableMethod callableMethod = callableGetter != null ? callableGetter : callableSetter; 1852 1853 propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); 1854 if (callableMethod == null) { 1855 owner = typeMapper.mapOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, 1856 isCallInsideSameModuleAsDeclared(propertyDescriptor, context)); 1857 } 1858 else { 1859 owner = callableMethod.getOwner(); 1860 } 1861 1862 String name; 1863 if (propertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) { 1864 assert backingFieldContext instanceof FieldOwnerContext : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext" ; 1865 name = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty); 1866 } else { 1867 name = JvmAbi.getDefaultPropertyName(propertyDescriptor.getName(), isDelegatedProperty, propertyDescriptor.getReceiverParameter() != null); 1868 } 1869 1870 return StackValue.property(propertyDescriptor, owner, 1871 typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), 1872 isStatic, name, callableGetter, callableSetter, state); 1873 1874 } 1875 1876 @Override 1877 public StackValue visitCallExpression(@NotNull JetCallExpression expression, StackValue receiver) { 1878 JetExpression callee = expression.getCalleeExpression(); 1879 assert callee != null; 1880 1881 ResolvedCall<?> resolvedCall = resolvedCall(callee); 1882 CallableDescriptor funDescriptor = resolvedCall.getResultingDescriptor(); 1883 1884 if (!(funDescriptor instanceof FunctionDescriptor)) { 1885 throw new UnsupportedOperationException("unknown type of callee descriptor: " + funDescriptor); 1886 } 1887 1888 funDescriptor = accessibleFunctionDescriptor((FunctionDescriptor) funDescriptor); 1889 1890 if (funDescriptor instanceof ConstructorDescriptor) { 1891 return generateNewCall(expression, resolvedCall, receiver); 1892 } 1893 1894 Call call = bindingContext.get(CALL, expression.getCalleeExpression()); 1895 if (funDescriptor.getOriginal() instanceof SamConstructorDescriptor) { 1896 //noinspection ConstantConditions 1897 SamType samType = SamType.create(funDescriptor.getReturnType()); 1898 assert samType != null : "SamType is not created for SAM constructor: " + funDescriptor; 1899 return invokeSamConstructor(expression, resolvedCall, samType); 1900 } 1901 1902 return invokeFunction(call, receiver, resolvedCall); 1903 } 1904 1905 @NotNull 1906 private StackValue invokeSamConstructor( 1907 @NotNull JetCallExpression expression, 1908 @NotNull ResolvedCall<?> resolvedCall, 1909 @NotNull SamType samType 1910 ) { 1911 List<ResolvedValueArgument> arguments = resolvedCall.getValueArgumentsByIndex(); 1912 if (arguments == null) { 1913 throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor()); 1914 } 1915 ResolvedValueArgument argument = arguments.get(0); 1916 if (!(argument instanceof ExpressionValueArgument)) { 1917 throw new IllegalStateException( 1918 "argument of SAM constructor is " + argument.getClass().getName() + " " + expression.getText()); 1919 } 1920 ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument(); 1921 assert valueArgument != null : "getValueArgument() is null for " + expression.getText(); 1922 JetExpression argumentExpression = valueArgument.getArgumentExpression(); 1923 assert argumentExpression != null : "getArgumentExpression() is null for " + expression.getText(); 1924 1925 return genSamInterfaceValue(argumentExpression, samType, this); 1926 } 1927 1928 @NotNull 1929 private StackValue genSamInterfaceValue( 1930 @NotNull JetExpression expression, 1931 @NotNull SamType samType, 1932 @NotNull JetVisitor<StackValue, StackValue> visitor 1933 ) { 1934 if (expression instanceof JetFunctionLiteralExpression) { 1935 return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samType, 1936 KotlinSyntheticClass.Kind.SAM_LAMBDA); 1937 } 1938 1939 Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile()); 1940 1941 v.anew(asmType); 1942 v.dup(); 1943 1944 Type functionType = typeMapper.mapType(samType.getKotlinFunctionType()); 1945 expression.accept(visitor, StackValue.none()).put(functionType, v); 1946 1947 Label ifNonNull = new Label(); 1948 Label afterAll = new Label(); 1949 1950 v.dup(); 1951 v.ifnonnull(ifNonNull); 1952 1953 // if null: pop function value and wrapper objects, put null 1954 v.pop(); 1955 v.pop2(); 1956 v.aconst(null); 1957 v.goTo(afterAll); 1958 1959 v.mark(ifNonNull); 1960 v.invokespecial(asmType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType)); 1961 1962 v.mark(afterAll); 1963 return StackValue.onStack(asmType); 1964 } 1965 1966 @NotNull 1967 private PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { 1968 return context.accessiblePropertyDescriptor(propertyDescriptor); 1969 } 1970 1971 @NotNull 1972 protected FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { 1973 return context.accessibleFunctionDescriptor(fd); 1974 } 1975 1976 @NotNull 1977 public StackValue invokeFunction(Call call, StackValue receiver, ResolvedCall<?> resolvedCall) { 1978 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1979 return invokeFunction(call, receiver, ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall()); 1980 } 1981 1982 FunctionDescriptor fd = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 1983 JetSuperExpression superCallExpression = getSuperCallExpression(call); 1984 boolean superCall = superCallExpression != null; 1985 1986 if (superCall && !isInterface(fd.getContainingDeclaration())) { 1987 ClassDescriptor owner = getSuperCallLabelTarget(superCallExpression); 1988 CodegenContext c = context.findParentContextWithDescriptor(owner); 1989 assert c != null : "Couldn't find a context for a super-call: " + fd; 1990 if (c != context.getParentContext()) { 1991 fd = (FunctionDescriptor) c.getAccessor(fd); 1992 } 1993 } 1994 1995 Callable callable = resolveToCallable(accessibleFunctionDescriptor(fd), superCall); 1996 1997 if (callable instanceof CallableMethod) { 1998 CallableMethod callableMethod = (CallableMethod) callable; 1999 invokeMethodWithArguments(call, callableMethod, resolvedCall, receiver); 2000 //noinspection ConstantConditions 2001 Type returnType = typeMapper.mapReturnType(resolvedCall.getResultingDescriptor()); 2002 StackValue.coerce(callableMethod.getReturnType(), returnType, v); 2003 return StackValue.onStack(returnType); 2004 } 2005 else { 2006 receiver = StackValue.receiver(resolvedCall, receiver, this, null); 2007 2008 List<JetExpression> args = new ArrayList<JetExpression>(); 2009 for (ValueArgument argument : call.getValueArguments()) { 2010 args.add(argument.getArgumentExpression()); 2011 } 2012 2013 Type returnType = typeMapper.mapType(resolvedCall.getResultingDescriptor()); 2014 2015 ((IntrinsicMethod) callable).generate(this, v, returnType, call.getCallElement(), args, receiver); 2016 return StackValue.onStack(returnType); 2017 } 2018 } 2019 2020 @Nullable 2021 private static JetSuperExpression getSuperCallExpression(@NotNull Call call) { 2022 ReceiverValue explicitReceiver = call.getExplicitReceiver(); 2023 if (explicitReceiver instanceof ExpressionReceiver) { 2024 JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression(); 2025 if (receiverExpression instanceof JetSuperExpression) { 2026 return (JetSuperExpression) receiverExpression; 2027 } 2028 } 2029 return null; 2030 } 2031 2032 // Find the first parent of the current context which corresponds to a subclass of a given class 2033 @NotNull 2034 private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) { 2035 CodegenContext c = context; 2036 while (true) { 2037 if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) { 2038 return c; 2039 } 2040 c = c.getParentContext(); 2041 assert c != null; 2042 } 2043 } 2044 2045 @NotNull 2046 Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall) { 2047 IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd); 2048 if (intrinsic != null) { 2049 return intrinsic; 2050 } 2051 2052 return resolveToCallableMethod(fd, superCall, context); 2053 } 2054 2055 @NotNull 2056 private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull CodegenContext context) { 2057 SimpleFunctionDescriptor originalOfSamAdapter = (SimpleFunctionDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(fd); 2058 return typeMapper.mapToCallableMethod(originalOfSamAdapter != null ? originalOfSamAdapter : fd, superCall, context); 2059 } 2060 2061 public void invokeMethodWithArguments( 2062 @Nullable Call call, 2063 @NotNull CallableMethod callableMethod, 2064 @NotNull ResolvedCall<?> resolvedCall, 2065 @NotNull StackValue receiver 2066 ) { 2067 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 2068 JetElement callElement = call != null ? call.getCallElement() : null; 2069 2070 CallGenerator callGenerator = getOrCreateCallGenerator(descriptor, callElement); 2071 2072 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 2073 resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall(); 2074 } 2075 2076 assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) : 2077 "Tail recursive method couldn't be inlined " + descriptor; 2078 2079 int mask = pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, callableMethod, false, callGenerator); 2080 2081 if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { 2082 tailRecursionCodegen.generateTailRecursion(resolvedCall); 2083 return; 2084 } 2085 2086 boolean callDefault = mask != 0; 2087 if (callDefault) { 2088 callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE)); 2089 } 2090 2091 callGenerator.genCall(callableMethod, resolvedCall, callDefault, this); 2092 } 2093 2094 @NotNull 2095 protected CallGenerator getOrCreateCallGenerator(@NotNull CallableDescriptor descriptor, @Nullable JetElement callElement) { 2096 boolean isInline = state.isInlineEnabled() && 2097 descriptor instanceof SimpleFunctionDescriptor && 2098 ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline(); 2099 2100 return !isInline || callElement == null ? defaultCallGenerator : 2101 new InlineCodegen(this, state, (SimpleFunctionDescriptor) DescriptorUtils.unwrapFakeOverride( 2102 (CallableMemberDescriptor) descriptor.getOriginal()), callElement); 2103 } 2104 2105 public void generateFromResolvedCall(@NotNull ReceiverValue descriptor, @NotNull Type type) { 2106 if (descriptor instanceof ClassReceiver) { 2107 Type exprType = asmType(descriptor.getType()); 2108 ClassReceiver classReceiver = (ClassReceiver) descriptor; 2109 ClassDescriptor classReceiverDeclarationDescriptor = classReceiver.getDeclarationDescriptor(); 2110 if (DescriptorUtils.isClassObject(classReceiverDeclarationDescriptor)) { 2111 if (context.getContextDescriptor() instanceof FunctionDescriptor && 2112 classReceiverDeclarationDescriptor == context.getContextDescriptor().getContainingDeclaration()) { 2113 v.load(0, OBJECT_TYPE); 2114 } 2115 else { 2116 FieldInfo info = FieldInfo.createForSingleton(classReceiverDeclarationDescriptor, typeMapper); 2117 v.getstatic(info.getOwnerInternalName(), info.getFieldName(), info.getFieldType().getDescriptor()); 2118 } 2119 StackValue.onStack(exprType).put(type, v); 2120 } 2121 else { 2122 StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor, false, false).put(type, v); 2123 } 2124 } 2125 else if (descriptor instanceof ScriptReceiver) { 2126 // SCRIPT: generate script 2127 generateScript((ScriptReceiver) descriptor); 2128 } 2129 else if (descriptor instanceof ExtensionReceiver) { 2130 ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor; 2131 generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v); 2132 } 2133 else if (descriptor instanceof ExpressionReceiver) { 2134 ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor; 2135 JetExpression expr = expressionReceiver.getExpression(); 2136 gen(expr, type); 2137 } 2138 else { 2139 throw new UnsupportedOperationException("Unsupported receiver type: " + descriptor); 2140 } 2141 } 2142 2143 @Nullable 2144 private static JetExpression getReceiverForSelector(PsiElement expression) { 2145 if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) { 2146 JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent(); 2147 return parent.getReceiverExpression(); 2148 } 2149 return null; 2150 } 2151 2152 private StackValue generateReceiver(DeclarationDescriptor provided) { 2153 if (context.getCallableDescriptorWithReceiver() == provided) { 2154 return context.getReceiverExpression(typeMapper); 2155 } 2156 2157 return context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false); 2158 } 2159 2160 // SCRIPT: generate script, move to ScriptingUtil 2161 private void generateScript(@NotNull ScriptReceiver receiver) { 2162 CodegenContext cur = context; 2163 StackValue result = StackValue.local(0, OBJECT_TYPE); 2164 boolean inStartConstructorContext = cur instanceof ConstructorContext; 2165 while (cur != null) { 2166 if (!inStartConstructorContext) { 2167 cur = getNotNullParentContextForMethod(cur); 2168 } 2169 2170 if (cur instanceof ScriptContext) { 2171 ScriptContext scriptContext = (ScriptContext) cur; 2172 2173 Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor()); 2174 if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) { 2175 result.put(currentScriptType, v); 2176 } 2177 else { 2178 Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor()); 2179 String fieldName = scriptContext.getScriptFieldName(receiver.getDeclarationDescriptor()); 2180 result.put(currentScriptType, v); 2181 StackValue.field(classType, currentScriptType, fieldName, false).put(classType, v); 2182 } 2183 return; 2184 } 2185 2186 result = cur.getOuterExpression(result, false); 2187 2188 if (inStartConstructorContext) { 2189 cur = getNotNullParentContextForMethod(cur); 2190 inStartConstructorContext = false; 2191 } 2192 2193 cur = cur.getParentContext(); 2194 } 2195 2196 throw new UnsupportedOperationException(); 2197 } 2198 2199 @NotNull 2200 public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) { 2201 boolean isSingleton = calleeContainingClass.getKind().isSingleton(); 2202 if (isSingleton) { 2203 if (context.hasThisDescriptor() && context.getThisDescriptor().equals(calleeContainingClass)) { 2204 return StackValue.local(0, typeMapper.mapType(calleeContainingClass)); 2205 } 2206 else { 2207 return StackValue.singleton(calleeContainingClass, typeMapper); 2208 } 2209 } 2210 2211 CodegenContext cur = context; 2212 Type type = asmType(calleeContainingClass.getDefaultType()); 2213 StackValue result = StackValue.local(0, type); 2214 boolean inStartConstructorContext = cur instanceof ConstructorContext; 2215 while (cur != null) { 2216 ClassDescriptor thisDescriptor = cur.getThisDescriptor(); 2217 2218 if (!isSuper && thisDescriptor == calleeContainingClass) { 2219 return result; 2220 } 2221 2222 if (isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { 2223 return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass); 2224 } 2225 2226 //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer 2227 if (inStartConstructorContext) { 2228 result = cur.getOuterExpression(result, false); 2229 cur = getNotNullParentContextForMethod(cur); 2230 inStartConstructorContext = false; 2231 } 2232 else { 2233 cur = getNotNullParentContextForMethod(cur); 2234 result = cur.getOuterExpression(result, false); 2235 } 2236 2237 cur = cur.getParentContext(); 2238 } 2239 2240 throw new UnsupportedOperationException(); 2241 } 2242 2243 @NotNull 2244 private static CodegenContext getNotNullParentContextForMethod(CodegenContext cur) { 2245 if (cur instanceof MethodContext) { 2246 cur = cur.getParentContext(); 2247 } 2248 assert cur != null; 2249 return cur; 2250 } 2251 2252 2253 private static boolean isReceiver(PsiElement expression) { 2254 PsiElement parent = expression.getParent(); 2255 if (parent instanceof JetQualifiedExpression) { 2256 JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression(); 2257 return expression == receiverExpression; 2258 } 2259 return false; 2260 } 2261 2262 public int pushMethodArgumentsWithCallReceiver( 2263 @Nullable StackValue receiver, 2264 @NotNull ResolvedCall<?> resolvedCall, 2265 @NotNull CallableMethod callableMethod, 2266 boolean skipLast, 2267 @NotNull CallGenerator callGenerator 2268 ) { 2269 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 2270 2271 if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already 2272 receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); 2273 receiver.put(receiver.type, v); 2274 } 2275 2276 callGenerator.putHiddenParams(); 2277 2278 return pushMethodArgumentsWithoutCallReceiver(resolvedCall, callableMethod.getValueParameterTypes(), skipLast, callGenerator); 2279 } 2280 2281 public int pushMethodArgumentsWithoutCallReceiver( 2282 @NotNull ResolvedCall<?> resolvedCall, 2283 List<Type> valueParameterTypes, 2284 boolean skipLast, 2285 @NotNull CallGenerator callGenerator 2286 ) { 2287 List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex(); 2288 CallableDescriptor fd = resolvedCall.getResultingDescriptor(); 2289 if (valueArguments == null) { 2290 throw new IllegalStateException("Failed to arrange value arguments by index: " + fd); 2291 } 2292 List<ValueParameterDescriptor> valueParameters = fd.getValueParameters(); 2293 2294 if (valueParameters.size() != valueArguments.size()) { 2295 throw new IllegalStateException("Parameters and arguments size mismatch: " + valueParameters.size() + " != " + valueArguments.size()); 2296 } 2297 2298 int mask = 0; 2299 2300 for (Iterator<ValueParameterDescriptor> iterator = valueParameters.iterator(); iterator.hasNext(); ) { 2301 ValueParameterDescriptor valueParameter = iterator.next(); 2302 if (skipLast && !iterator.hasNext()) { 2303 continue; 2304 } 2305 2306 ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); 2307 Type parameterType = valueParameterTypes.get(valueParameter.getIndex()); 2308 if (resolvedValueArgument instanceof ExpressionValueArgument) { 2309 ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument(); 2310 assert valueArgument != null; 2311 JetExpression argumentExpression = valueArgument.getArgumentExpression(); 2312 assert argumentExpression != null : valueArgument.asElement().getText(); 2313 2314 callGenerator.genValueAndPut(valueParameter, argumentExpression, parameterType); 2315 } else if (resolvedValueArgument instanceof DefaultValueArgument) { 2316 pushDefaultValueOnStack(parameterType, v); 2317 mask |= (1 << valueParameter.getIndex()); 2318 callGenerator.afterParameterPut(parameterType, null, valueParameter); 2319 } 2320 else if (resolvedValueArgument instanceof VarargValueArgument) { 2321 VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument; 2322 genVarargs(valueParameter, valueArgument); 2323 callGenerator.afterParameterPut(parameterType, null, valueParameter); 2324 } 2325 else { 2326 throw new UnsupportedOperationException(); 2327 } 2328 } 2329 return mask; 2330 } 2331 2332 public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) { 2333 JetType outType = valueParameterDescriptor.getType(); 2334 2335 Type type = asmType(outType); 2336 assert type.getSort() == Type.ARRAY; 2337 Type elementType = correctElementType(type); 2338 List<ValueArgument> arguments = valueArgument.getArguments(); 2339 int size = arguments.size(); 2340 2341 boolean hasSpread = false; 2342 for (int i = 0; i != size; ++i) { 2343 if (arguments.get(i).getSpreadElement() != null) { 2344 hasSpread = true; 2345 break; 2346 } 2347 } 2348 2349 if (hasSpread) { 2350 if (size == 1) { 2351 gen(arguments.get(0).getArgumentExpression(), type); 2352 } 2353 else { 2354 String owner = "kotlin/jvm/internal/SpreadBuilder"; 2355 v.anew(Type.getObjectType(owner)); 2356 v.dup(); 2357 v.invokespecial(owner, "<init>", "()V"); 2358 for (int i = 0; i != size; ++i) { 2359 v.dup(); 2360 ValueArgument argument = arguments.get(i); 2361 if (argument.getSpreadElement() != null) { 2362 gen(argument.getArgumentExpression(), OBJECT_TYPE); 2363 v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V"); 2364 } 2365 else { 2366 gen(argument.getArgumentExpression(), elementType); 2367 v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z"); 2368 v.pop(); 2369 } 2370 } 2371 v.dup(); 2372 v.invokevirtual(owner, "size", "()I"); 2373 v.newarray(elementType); 2374 v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;"); 2375 v.checkcast(type); 2376 } 2377 } 2378 else { 2379 v.iconst(arguments.size()); 2380 v.newarray(elementType); 2381 for (int i = 0; i != size; ++i) { 2382 v.dup(); 2383 v.iconst(i); 2384 gen(arguments.get(i).getArgumentExpression(), elementType); 2385 StackValue.arrayElement(elementType).store(elementType, v); 2386 } 2387 } 2388 } 2389 2390 public int indexOfLocal(JetReferenceExpression lhs) { 2391 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs); 2392 if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) { 2393 return -1; 2394 } 2395 return lookupLocalIndex(declarationDescriptor); 2396 } 2397 2398 @Override 2399 public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) { 2400 // TODO: properties 2401 FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); 2402 assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText(); 2403 2404 CallableReferenceGenerationStrategy strategy = 2405 new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall(expression.getCallableReference())); 2406 ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context, 2407 KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, 2408 this, strategy, getParentCodegen()); 2409 2410 closureCodegen.gen(); 2411 2412 return closureCodegen.putInstanceOnStack(v, this); 2413 } 2414 2415 private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased<FunctionDescriptor> { 2416 private final ResolvedCall<?> resolvedCall; 2417 private final FunctionDescriptor referencedFunction; 2418 2419 public CallableReferenceGenerationStrategy( 2420 @NotNull GenerationState state, 2421 @NotNull FunctionDescriptor functionDescriptor, 2422 @NotNull ResolvedCall<?> resolvedCall 2423 ) { 2424 super(state, functionDescriptor); 2425 this.resolvedCall = resolvedCall; 2426 this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2427 } 2428 2429 @Override 2430 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 2431 /* 2432 Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation 2433 of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of 2434 ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every 2435 argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of 2436 every argument boils down to calling LOAD with the corresponding index 2437 */ 2438 2439 JetCallExpression fakeExpression = constructFakeFunctionCall(); 2440 final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments(); 2441 2442 final ReceiverValue thisObject = computeAndSaveReceiver(signature, codegen, referencedFunction.getExpectedThisObject()); 2443 final ReceiverValue extensionReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getReceiverParameter()); 2444 computeAndSaveArguments(fakeArguments, codegen); 2445 2446 ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) { 2447 @NotNull 2448 @Override 2449 public ReceiverValue getReceiverArgument() { 2450 return extensionReceiver; 2451 } 2452 2453 @NotNull 2454 @Override 2455 public ReceiverValue getThisObject() { 2456 return thisObject; 2457 } 2458 2459 @NotNull 2460 @Override 2461 public List<ResolvedValueArgument> getValueArgumentsByIndex() { 2462 List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size()); 2463 for (ValueArgument argument : fakeArguments) { 2464 result.add(new ExpressionValueArgument(argument)); 2465 } 2466 return result; 2467 } 2468 }; 2469 2470 StackValue result; 2471 Type returnType = codegen.returnType; 2472 if (referencedFunction instanceof ConstructorDescriptor) { 2473 if (returnType.getSort() == Type.ARRAY) { 2474 //noinspection ConstantConditions 2475 codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType()); 2476 result = StackValue.onStack(returnType); 2477 } 2478 else { 2479 result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType); 2480 } 2481 } 2482 else { 2483 Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); 2484 result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall); 2485 } 2486 2487 InstructionAdapter v = codegen.v; 2488 result.put(returnType, v); 2489 v.areturn(returnType); 2490 } 2491 2492 @NotNull 2493 private JetCallExpression constructFakeFunctionCall() { 2494 StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall("); 2495 for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) { 2496 ValueParameterDescriptor descriptor = iterator.next(); 2497 fakeFunctionCall.append("p").append(descriptor.getIndex()); 2498 if (iterator.hasNext()) { 2499 fakeFunctionCall.append(", "); 2500 } 2501 } 2502 fakeFunctionCall.append(")"); 2503 return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString()); 2504 } 2505 2506 private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) { 2507 for (ValueParameterDescriptor parameter : callableDescriptor.getValueParameters()) { 2508 ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex()); 2509 Type type = state.getTypeMapper().mapType(parameter); 2510 int localIndex = codegen.myFrameMap.getIndex(parameter); 2511 codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type)); 2512 } 2513 } 2514 2515 @NotNull 2516 private ReceiverValue computeAndSaveReceiver( 2517 @NotNull JvmMethodSignature signature, 2518 @NotNull ExpressionCodegen codegen, 2519 @Nullable ReceiverParameterDescriptor receiver 2520 ) { 2521 if (receiver == null) return NO_RECEIVER; 2522 2523 JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(), "callableReferenceFakeReceiver"); 2524 codegen.tempVariables.put(receiverExpression, receiverParameterStackValue(signature)); 2525 return new ExpressionReceiver(receiverExpression, receiver.getType()); 2526 } 2527 2528 @NotNull 2529 private static StackValue.Local receiverParameterStackValue(@NotNull JvmMethodSignature signature) { 2530 // 0 is this (the callable reference class), 1 is the invoke() method's first parameter 2531 return StackValue.local(1, signature.getAsmMethod().getArgumentTypes()[0]); 2532 } 2533 } 2534 2535 @Override 2536 public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) { 2537 StackValue receiverValue = StackValue.none(); 2538 return genQualified(receiverValue, expression.getSelectorExpression()); 2539 } 2540 2541 @Override 2542 public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue unused) { 2543 JetExpression receiver = expression.getReceiverExpression(); 2544 JetExpression selector = expression.getSelectorExpression(); 2545 Type type = boxType(expressionType(expression)); 2546 Type receiverType = expressionType(receiver); 2547 2548 gen(receiver, receiverType); 2549 2550 if (isPrimitive(receiverType)) { 2551 StackValue propValue = genQualified(StackValue.onStack(receiverType), selector); 2552 propValue.put(type, v); 2553 2554 return StackValue.onStack(type); 2555 } 2556 2557 Label ifnull = new Label(); 2558 Label end = new Label(); 2559 v.dup(); 2560 v.ifnull(ifnull); 2561 StackValue propValue = genQualified(StackValue.onStack(receiverType), selector); 2562 propValue.put(type, v); 2563 v.goTo(end); 2564 2565 v.mark(ifnull); 2566 v.pop(); 2567 if (!type.equals(Type.VOID_TYPE)) { 2568 v.aconst(null); 2569 } 2570 v.mark(end); 2571 2572 return StackValue.onStack(type); 2573 } 2574 2575 @Override 2576 public StackValue visitBinaryExpression(@NotNull JetBinaryExpression expression, StackValue receiver) { 2577 JetSimpleNameExpression reference = expression.getOperationReference(); 2578 IElementType opToken = reference.getReferencedNameElementType(); 2579 if (opToken == JetTokens.EQ) { 2580 return generateAssignmentExpression(expression); 2581 } 2582 else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { 2583 return generateAugmentedAssignment(expression); 2584 } 2585 else if (opToken == JetTokens.ANDAND) { 2586 return generateBooleanAnd(expression); 2587 } 2588 else if (opToken == JetTokens.OROR) { 2589 return generateBooleanOr(expression); 2590 } 2591 else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ || 2592 opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { 2593 return generateEquals(expression.getLeft(), expression.getRight(), opToken); 2594 } 2595 else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ || 2596 opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { 2597 return generateComparison(expression, receiver); 2598 } 2599 else if (opToken == JetTokens.ELVIS) { 2600 return generateElvis(expression); 2601 } 2602 else if (opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) { 2603 return generateIn(StackValue.expression(Type.INT_TYPE, expression.getLeft(), this), expression.getRight(), reference); 2604 } 2605 else { 2606 ResolvedCall<?> resolvedCall = resolvedCall(reference); 2607 FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2608 2609 Callable callable = resolveToCallable(descriptor, false); 2610 if (callable instanceof IntrinsicMethod) { 2611 Type returnType = typeMapper.mapType(descriptor); 2612 ((IntrinsicMethod) callable).generate(this, v, returnType, expression, 2613 Arrays.asList(expression.getLeft(), expression.getRight()), receiver); 2614 return StackValue.onStack(returnType); 2615 } 2616 2617 Call call = bindingContext.get(CALL, reference); 2618 return invokeFunction(call, receiver, resolvedCall); 2619 } 2620 } 2621 2622 private StackValue generateIn(StackValue leftValue, JetExpression rangeExpression, JetSimpleNameExpression operationReference) { 2623 JetExpression deparenthesized = JetPsiUtil.deparenthesize(rangeExpression); 2624 if (isIntRangeExpr(deparenthesized)) { 2625 genInIntRange(leftValue, (JetBinaryExpression) deparenthesized); 2626 } 2627 else { 2628 invokeFunction( 2629 bindingContext.get(CALL, operationReference), 2630 StackValue.none(), 2631 resolvedCall(operationReference) 2632 ); 2633 } 2634 if (operationReference.getReferencedNameElementType() == JetTokens.NOT_IN) { 2635 genInvertBoolean(v); 2636 } 2637 return StackValue.onStack(Type.BOOLEAN_TYPE); 2638 } 2639 2640 private void genInIntRange(StackValue leftValue, JetBinaryExpression rangeExpression) { 2641 v.iconst(1); 2642 // 1 2643 leftValue.put(Type.INT_TYPE, v); 2644 // 1 l 2645 v.dup2(); 2646 // 1 l 1 l 2647 2648 //noinspection ConstantConditions 2649 gen(rangeExpression.getLeft(), Type.INT_TYPE); 2650 // 1 l 1 l r 2651 Label lok = new Label(); 2652 v.ificmpge(lok); 2653 // 1 l 1 2654 v.pop(); 2655 v.iconst(0); 2656 v.mark(lok); 2657 // 1 l c 2658 v.dupX2(); 2659 // c 1 l c 2660 v.pop(); 2661 // c 1 l 2662 2663 gen(rangeExpression.getRight(), Type.INT_TYPE); 2664 // c 1 l r 2665 Label rok = new Label(); 2666 v.ificmple(rok); 2667 // c 1 2668 v.pop(); 2669 v.iconst(0); 2670 v.mark(rok); 2671 // c c 2672 2673 v.and(Type.INT_TYPE); 2674 } 2675 2676 private StackValue generateBooleanAnd(JetBinaryExpression expression) { 2677 gen(expression.getLeft(), Type.BOOLEAN_TYPE); 2678 Label ifFalse = new Label(); 2679 v.ifeq(ifFalse); 2680 gen(expression.getRight(), Type.BOOLEAN_TYPE); 2681 Label end = new Label(); 2682 v.goTo(end); 2683 v.mark(ifFalse); 2684 v.iconst(0); 2685 v.mark(end); 2686 return StackValue.onStack(Type.BOOLEAN_TYPE); 2687 } 2688 2689 private StackValue generateBooleanOr(JetBinaryExpression expression) { 2690 gen(expression.getLeft(), Type.BOOLEAN_TYPE); 2691 Label ifTrue = new Label(); 2692 v.ifne(ifTrue); 2693 gen(expression.getRight(), Type.BOOLEAN_TYPE); 2694 Label end = new Label(); 2695 v.goTo(end); 2696 v.mark(ifTrue); 2697 v.iconst(1); 2698 v.mark(end); 2699 return StackValue.onStack(Type.BOOLEAN_TYPE); 2700 } 2701 2702 private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) { 2703 Type leftType = expressionType(left); 2704 Type rightType = expressionType(right); 2705 2706 if (JetPsiUtil.isNullConstant(left)) { 2707 return genCmpWithNull(right, rightType, opToken); 2708 } 2709 2710 if (JetPsiUtil.isNullConstant(right)) { 2711 return genCmpWithNull(left, leftType, opToken); 2712 } 2713 2714 if (isIntZero(left, leftType) && isIntPrimitive(rightType)) { 2715 return genCmpWithZero(right, rightType, opToken); 2716 } 2717 2718 if (isIntZero(right, rightType) && isIntPrimitive(leftType)) { 2719 return genCmpWithZero(left, leftType, opToken); 2720 } 2721 2722 if (isPrimitive(leftType) != isPrimitive(rightType)) { 2723 leftType = boxType(leftType); 2724 gen(left, leftType); 2725 rightType = boxType(rightType); 2726 gen(right, rightType); 2727 } 2728 else { 2729 gen(left, leftType); 2730 gen(right, rightType); 2731 } 2732 2733 return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType); 2734 } 2735 2736 private boolean isIntZero(JetExpression expr, Type exprType) { 2737 CompileTimeConstant<?> exprValue = getCompileTimeConstant(expr, bindingContext); 2738 return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue()); 2739 } 2740 2741 private StackValue genCmpWithZero(JetExpression exp, Type expType, IElementType opToken) { 2742 v.iconst(1); 2743 gen(exp, expType); 2744 Label ok = new Label(); 2745 if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { 2746 v.ifeq(ok); 2747 } 2748 else { 2749 v.ifne(ok); 2750 } 2751 v.pop(); 2752 v.iconst(0); 2753 v.mark(ok); 2754 return StackValue.onStack(Type.BOOLEAN_TYPE); 2755 } 2756 2757 private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) { 2758 v.iconst(1); 2759 gen(exp, boxType(expType)); 2760 Label ok = new Label(); 2761 if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { 2762 v.ifnull(ok); 2763 } 2764 else { 2765 v.ifnonnull(ok); 2766 } 2767 v.pop(); 2768 v.iconst(0); 2769 v.mark(ok); 2770 return StackValue.onStack(Type.BOOLEAN_TYPE); 2771 } 2772 2773 private StackValue generateElvis(JetBinaryExpression expression) { 2774 Type exprType = expressionType(expression); 2775 Type leftType = expressionType(expression.getLeft()); 2776 2777 gen(expression.getLeft(), leftType); 2778 2779 if (isPrimitive(leftType)) { 2780 return StackValue.onStack(leftType); 2781 } 2782 2783 v.dup(); 2784 Label ifNull = new Label(); 2785 v.ifnull(ifNull); 2786 StackValue.onStack(leftType).put(exprType, v); 2787 Label end = new Label(); 2788 v.goTo(end); 2789 v.mark(ifNull); 2790 v.pop(); 2791 gen(expression.getRight(), exprType); 2792 v.mark(end); 2793 2794 return StackValue.onStack(exprType); 2795 } 2796 2797 private StackValue generateComparison(JetBinaryExpression expression, StackValue receiver) { 2798 ResolvedCall<?> resolvedCall = resolvedCall(expression.getOperationReference()); 2799 FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2800 2801 JetExpression left = expression.getLeft(); 2802 JetExpression right = expression.getRight(); 2803 Callable callable = resolveToCallable(descriptor, false); 2804 2805 Type type; 2806 if (callable instanceof IntrinsicMethod) { 2807 // Compare two primitive values 2808 type = comparisonOperandType(expressionType(left), expressionType(right)); 2809 StackValue recv = gen(left); 2810 recv.put(type, v); 2811 gen(right, type); 2812 } 2813 else { 2814 Call call = bindingContext.get(CALL, expression.getOperationReference()); 2815 StackValue result = invokeFunction(call, receiver, resolvedCall); 2816 type = Type.INT_TYPE; 2817 result.put(type, v); 2818 v.iconst(0); 2819 } 2820 return StackValue.cmp(expression.getOperationToken(), type); 2821 } 2822 2823 private StackValue generateAssignmentExpression(JetBinaryExpression expression) { 2824 StackValue stackValue = gen(expression.getLeft()); 2825 JetExpression right = expression.getRight(); 2826 assert right != null : expression.getText(); 2827 gen(right, stackValue.type); 2828 stackValue.store(stackValue.type, v); 2829 return StackValue.none(); 2830 } 2831 2832 private StackValue generateAugmentedAssignment(JetBinaryExpression expression) { 2833 ResolvedCall<?> resolvedCall = resolvedCall(expression.getOperationReference()); 2834 FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 2835 Callable callable = resolveToCallable(descriptor, false); 2836 JetExpression lhs = expression.getLeft(); 2837 Type lhsType = expressionType(lhs); 2838 2839 boolean keepReturnValue; 2840 if (Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))) { 2841 if (callable instanceof IntrinsicMethod) { 2842 StackValue value = gen(lhs); // receiver 2843 value.dupReceiver(v); // receiver receiver 2844 value.put(lhsType, v); // receiver lhs 2845 ((IntrinsicMethod) callable).generate(this, v, typeMapper.mapType(descriptor), expression, 2846 Collections.singletonList(expression.getRight()), StackValue.onStack(lhsType)); 2847 value.store(lhsType, v); 2848 return StackValue.none(); 2849 } 2850 else { 2851 keepReturnValue = true; 2852 } 2853 } 2854 else { 2855 keepReturnValue = !KotlinBuiltIns.getInstance().getUnitType().equals(descriptor.getReturnType()); 2856 } 2857 2858 callAugAssignMethod(expression, resolvedCall, (CallableMethod) callable, lhsType, keepReturnValue); 2859 2860 return StackValue.none(); 2861 } 2862 2863 private void callAugAssignMethod( 2864 @NotNull JetBinaryExpression expression, 2865 @NotNull ResolvedCall<?> resolvedCall, 2866 @NotNull CallableMethod callable, 2867 @NotNull Type lhsType, 2868 boolean keepReturnValue 2869 ) { 2870 Call call = bindingContext.get(CALL, expression.getOperationReference()); 2871 assert call != null : "Call should be not null for operation reference in " + expression.getText(); 2872 2873 StackValue value = gen(expression.getLeft()); 2874 if (keepReturnValue) { 2875 value.dupReceiver(v); 2876 } 2877 value.put(lhsType, v); 2878 StackValue receiver = StackValue.onStack(lhsType); 2879 2880 invokeMethodWithArguments(call, callable, resolvedCall, receiver); 2881 2882 if (keepReturnValue) { 2883 value.store(callable.getReturnType(), v); 2884 } 2885 } 2886 2887 public void invokeAppend(JetExpression expr) { 2888 if (expr instanceof JetBinaryExpression) { 2889 JetBinaryExpression binaryExpression = (JetBinaryExpression) expr; 2890 if (binaryExpression.getOperationToken() == JetTokens.PLUS) { 2891 JetExpression left = binaryExpression.getLeft(); 2892 JetExpression right = binaryExpression.getRight(); 2893 Type leftType = expressionType(left); 2894 Type rightType = expressionType(right); 2895 2896 if (leftType.equals(JAVA_STRING_TYPE) && rightType.equals(JAVA_STRING_TYPE)) { 2897 invokeAppend(left); 2898 invokeAppend(right); 2899 return; 2900 } 2901 } 2902 } 2903 Type exprType = expressionType(expr); 2904 gen(expr, exprType); 2905 genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType); 2906 } 2907 2908 @Nullable 2909 private static JetSimpleNameExpression targetLabel(JetExpression expression) { 2910 if (expression.getParent() instanceof JetLabeledExpression) { 2911 return ((JetLabeledExpression) expression.getParent()).getTargetLabel(); 2912 } 2913 return null; 2914 } 2915 2916 @Override 2917 public StackValue visitLabeledExpression( 2918 @NotNull JetLabeledExpression expression, StackValue receiver 2919 ) { 2920 return genQualified(receiver, expression.getBaseExpression()); 2921 } 2922 2923 @Override 2924 public StackValue visitPrefixExpression(@NotNull JetPrefixExpression expression, StackValue receiver) { 2925 DeclarationDescriptor op = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference()); 2926 assert op instanceof FunctionDescriptor : String.valueOf(op); 2927 Callable callable = resolveToCallable((FunctionDescriptor) op, false); 2928 if (callable instanceof IntrinsicMethod) { 2929 Type returnType = typeMapper.mapType((FunctionDescriptor) op); 2930 ((IntrinsicMethod) callable).generate(this, v, returnType, expression, 2931 Collections.singletonList(expression.getBaseExpression()), receiver); 2932 return StackValue.onStack(returnType); 2933 } 2934 2935 DeclarationDescriptor cls = op.getContainingDeclaration(); 2936 ResolvedCall<?> resolvedCall = resolvedCall(expression.getOperationReference()); 2937 2938 if (isPrimitiveNumberClassDescriptor(cls) || !(op.getName().asString().equals("inc") || op.getName().asString().equals("dec"))) { 2939 Call call = bindingContext.get(CALL, expression.getOperationReference()); 2940 return invokeFunction(call, receiver, resolvedCall); 2941 } 2942 2943 CallableMethod callableMethod = (CallableMethod) callable; 2944 2945 StackValue value = gen(expression.getBaseExpression()); 2946 value.dupReceiver(v); 2947 value.dupReceiver(v); 2948 2949 Type type = expressionType(expression.getBaseExpression()); 2950 value.put(type, v); 2951 callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall); 2952 2953 value.store(callableMethod.getReturnType(), v); 2954 value.put(type, v); 2955 return StackValue.onStack(type); 2956 } 2957 2958 @Override 2959 public StackValue visitPostfixExpression(@NotNull JetPostfixExpression expression, StackValue receiver) { 2960 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) { 2961 StackValue base = genQualified(receiver, expression.getBaseExpression()); 2962 if (isPrimitive(base.type)) { 2963 return base; 2964 } 2965 base.put(base.type, v); 2966 v.dup(); 2967 Label ok = new Label(); 2968 v.ifnonnull(ok); 2969 v.invokestatic("kotlin/jvm/internal/Intrinsics", "throwNpe", "()V"); 2970 v.mark(ok); 2971 return StackValue.onStack(base.type); 2972 } 2973 2974 DeclarationDescriptor op = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference()); 2975 if (!(op instanceof FunctionDescriptor)) { 2976 throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op); 2977 } 2978 2979 Type asmType = expressionType(expression); 2980 DeclarationDescriptor cls = op.getContainingDeclaration(); 2981 2982 int increment; 2983 if (op.getName().asString().equals("inc")) { 2984 increment = 1; 2985 } 2986 else if (op.getName().asString().equals("dec")) { 2987 increment = -1; 2988 } 2989 else { 2990 throw new UnsupportedOperationException("Unsupported postfix operation: " + op); 2991 } 2992 2993 boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls); 2994 if (isPrimitiveNumberClassDescriptor) { 2995 JetExpression operand = expression.getBaseExpression(); 2996 if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) { 2997 int index = indexOfLocal((JetReferenceExpression) operand); 2998 if (index >= 0) { 2999 return StackValue.postIncrement(index, increment); 3000 } 3001 } 3002 } 3003 3004 StackValue value = gen(expression.getBaseExpression()); 3005 value.dupReceiver(v); 3006 3007 Type type = expressionType(expression.getBaseExpression()); 3008 value.put(type, v); // old value 3009 3010 pushReceiverAndValueViaDup(value, type); // receiver and new value 3011 3012 Type storeType; 3013 if (isPrimitiveNumberClassDescriptor) { 3014 genIncrement(asmType, increment, v); 3015 storeType = type; 3016 } 3017 else { 3018 ResolvedCall<?> resolvedCall = resolvedCall(expression.getOperationReference()); 3019 Callable callable = resolveToCallable((FunctionDescriptor) op, false); 3020 CallableMethod callableMethod = (CallableMethod) callable; 3021 callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall); 3022 storeType = callableMethod.getReturnType(); 3023 } 3024 3025 value.store(storeType, v); 3026 return StackValue.onStack(asmType); // old value 3027 } 3028 3029 private void pushReceiverAndValueViaDup(StackValue value, Type type) { 3030 switch (value.receiverSize()) { 3031 case 0: 3032 dup(v, type); 3033 break; 3034 3035 case 1: 3036 if (type.getSize() == 2) { 3037 v.dup2X1(); 3038 } 3039 else { 3040 v.dupX1(); 3041 } 3042 break; 3043 3044 case 2: 3045 if (type.getSize() == 2) { 3046 v.dup2X2(); 3047 } 3048 else { 3049 v.dupX2(); 3050 } 3051 break; 3052 3053 case -1: 3054 throw new UnsupportedOperationException(); 3055 } 3056 } 3057 3058 @Override 3059 public StackValue visitProperty(@NotNull JetProperty property, StackValue receiver) { 3060 final JetExpression initializer = property.getInitializer(); 3061 if (initializer == null) { 3062 return StackValue.none(); 3063 } 3064 initializeLocalVariable(property, new Function<VariableDescriptor, Void>() { 3065 @Override 3066 public Void fun(VariableDescriptor descriptor) { 3067 Type varType = asmType(descriptor.getType()); 3068 gen(initializer, varType); 3069 return null; 3070 } 3071 }); 3072 return StackValue.none(); 3073 } 3074 3075 @Override 3076 public StackValue visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, StackValue receiver) { 3077 JetExpression initializer = multiDeclaration.getInitializer(); 3078 if (initializer == null) return StackValue.none(); 3079 3080 JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer); 3081 assert initializerType != null; 3082 3083 Type initializerAsmType = asmType(initializerType); 3084 3085 final TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType); 3086 3087 int tempVarIndex = myFrameMap.enterTemp(initializerAsmType); 3088 3089 gen(initializer, initializerAsmType); 3090 v.store(tempVarIndex, initializerAsmType); 3091 final StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType); 3092 3093 for (final JetMultiDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) { 3094 initializeLocalVariable(variableDeclaration, new Function<VariableDescriptor, Void>() { 3095 @Override 3096 public Void fun(VariableDescriptor descriptor) { 3097 ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration); 3098 assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); 3099 Call call = makeFakeCall(initializerAsReceiver); 3100 invokeFunction(call, local, resolvedCall); 3101 return null; 3102 } 3103 }); 3104 } 3105 3106 if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) { 3107 v.aconst(null); 3108 v.store(tempVarIndex, initializerAsmType); 3109 } 3110 myFrameMap.leaveTemp(initializerAsmType); 3111 3112 return StackValue.none(); 3113 } 3114 3115 private void initializeLocalVariable( 3116 @NotNull JetVariableDeclaration variableDeclaration, 3117 @NotNull Function<VariableDescriptor, Void> generateInitializer 3118 ) { 3119 VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration); 3120 3121 if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) { 3122 return; 3123 } 3124 int index = lookupLocalIndex(variableDescriptor); 3125 3126 if (index < 0) { 3127 throw new IllegalStateException("Local variable not found for " + variableDescriptor); 3128 } 3129 3130 Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); 3131 assert variableDescriptor != null; 3132 3133 Type varType = asmType(variableDescriptor.getType()); 3134 3135 // SCRIPT: Variable at the top of the script is generated as field 3136 if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) { 3137 generateInitializer.fun(variableDescriptor); 3138 JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration); 3139 assert scriptPsi != null; 3140 Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi); 3141 v.putfield(scriptClassType.getInternalName(), variableDeclaration.getName(), varType.getDescriptor()); 3142 } 3143 else if (sharedVarType == null) { 3144 generateInitializer.fun(variableDescriptor); 3145 v.store(index, varType); 3146 } 3147 else { 3148 v.load(index, OBJECT_TYPE); 3149 generateInitializer.fun(variableDescriptor); 3150 v.putfield(sharedVarType.getInternalName(), "element", 3151 sharedVarType.equals(OBJECT_REF_TYPE) ? "Ljava/lang/Object;" : varType.getDescriptor()); 3152 } 3153 } 3154 3155 @NotNull 3156 private StackValue generateNewCall( 3157 @NotNull JetCallExpression expression, 3158 @NotNull ResolvedCall<?> resolvedCall, 3159 @NotNull StackValue receiver 3160 ) { 3161 Type type = expressionType(expression); 3162 if (type.getSort() == Type.ARRAY) { 3163 generateNewArray(expression); 3164 return StackValue.onStack(type); 3165 } 3166 3167 return generateConstructorCall(resolvedCall, receiver, type); 3168 } 3169 3170 @NotNull 3171 private StackValue generateConstructorCall(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver, @NotNull Type type) { 3172 v.anew(type); 3173 v.dup(); 3174 3175 receiver = StackValue.receiver(resolvedCall, receiver, this, null); 3176 receiver.put(receiver.type, v); 3177 3178 ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); 3179 MutableClosure closure = bindingContext.get(CLOSURE, constructorDescriptor.getContainingDeclaration()); 3180 3181 //Resolved call to local class constructor doesn't have resolvedCall.getThisObject() and resolvedCall.getReceiverArgument() 3182 //so we need generate closure on stack 3183 //See StackValue.receiver for more info 3184 pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists(), 3185 defaultCallGenerator); 3186 3187 ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructorDescriptor); 3188 CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructorDescriptor : originalOfSamAdapter); 3189 invokeMethodWithArguments(null, method, resolvedCall, StackValue.none()); 3190 3191 return StackValue.onStack(type); 3192 } 3193 3194 public void generateNewArray(@NotNull JetCallExpression expression) { 3195 JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression); 3196 assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText(); 3197 3198 generateNewArray(expression, arrayType); 3199 } 3200 3201 private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) { 3202 List<JetExpression> args = new ArrayList<JetExpression>(); 3203 for (ValueArgument va : expression.getValueArguments()) { 3204 args.add(va.getArgumentExpression()); 3205 } 3206 args.addAll(expression.getFunctionLiteralArguments()); 3207 3208 boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType); 3209 if (!isArray && args.size() != 1) { 3210 throw new CompilationException("primitive array constructor requires one argument", null, expression); 3211 } 3212 3213 if (isArray) { 3214 gen(args.get(0), Type.INT_TYPE); 3215 v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType()))); 3216 } 3217 else { 3218 Type type = typeMapper.mapType(arrayType); 3219 gen(args.get(0), Type.INT_TYPE); 3220 v.newarray(correctElementType(type)); 3221 } 3222 3223 if (args.size() == 2) { 3224 int sizeIndex = myFrameMap.enterTemp(Type.INT_TYPE); 3225 int indexIndex = myFrameMap.enterTemp(Type.INT_TYPE); 3226 3227 v.dup(); 3228 v.arraylength(); 3229 v.store(sizeIndex, Type.INT_TYPE); 3230 3231 v.iconst(0); 3232 v.store(indexIndex, Type.INT_TYPE); 3233 3234 gen(args.get(1), FUNCTION1_TYPE); 3235 3236 Label begin = new Label(); 3237 Label end = new Label(); 3238 v.visitLabel(begin); 3239 v.load(indexIndex, Type.INT_TYPE); 3240 v.load(sizeIndex, Type.INT_TYPE); 3241 v.ificmpge(end); 3242 3243 v.dup2(); 3244 v.load(indexIndex, Type.INT_TYPE); 3245 v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); 3246 v.invokeinterface(FUNCTION1_TYPE.getInternalName(), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;"); 3247 v.load(indexIndex, Type.INT_TYPE); 3248 v.iinc(indexIndex, 1); 3249 v.swap(); 3250 v.astore(OBJECT_TYPE); 3251 3252 v.goTo(begin); 3253 v.visitLabel(end); 3254 v.pop(); 3255 3256 myFrameMap.leaveTemp(Type.INT_TYPE); 3257 myFrameMap.leaveTemp(Type.INT_TYPE); 3258 } 3259 } 3260 3261 @Override 3262 public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) { 3263 JetExpression array = expression.getArrayExpression(); 3264 JetType type = bindingContext.get(EXPRESSION_TYPE, array); 3265 Type arrayType = expressionType(array); 3266 List<JetExpression> indices = expression.getIndexExpressions(); 3267 FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression); 3268 assert operationDescriptor != null; 3269 if (arrayType.getSort() == Type.ARRAY && 3270 indices.size() == 1 && 3271 operationDescriptor.getValueParameters().get(0).getType().equals(KotlinBuiltIns.getInstance().getIntType())) { 3272 gen(array, arrayType); 3273 for (JetExpression index : indices) { 3274 gen(index, Type.INT_TYPE); 3275 } 3276 assert type != null; 3277 if (KotlinBuiltIns.getInstance().isArray(type)) { 3278 JetType elementType = type.getArguments().get(0).getType(); 3279 return StackValue.arrayElement(boxType(asmType(elementType))); 3280 } 3281 else { 3282 return StackValue.arrayElement(correctElementType(arrayType)); 3283 } 3284 } 3285 else { 3286 ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression); 3287 ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression); 3288 3289 boolean isGetter = "get".equals(operationDescriptor.getName().asString()); 3290 3291 ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall; 3292 assert resolvedCall != null : "couldn't find resolved call: " + expression.getText(); 3293 3294 Callable callable = resolveToCallable(operationDescriptor, false); 3295 Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getAsmMethod(); 3296 Type[] argumentTypes = asmMethod.getArgumentTypes(); 3297 3298 if (callable instanceof CallableMethod) { 3299 boolean skipLast = !isGetter; 3300 pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, (CallableMethod) callable, skipLast, defaultCallGenerator); 3301 } 3302 else { 3303 gen(array, arrayType); // intrinsic method 3304 3305 int index = operationDescriptor.getReceiverParameter() != null ? 1 : 0; 3306 3307 for (JetExpression jetExpression : expression.getIndexExpressions()) { 3308 gen(jetExpression, argumentTypes[index]); 3309 index++; 3310 } 3311 } 3312 3313 Type elementType = isGetter ? asmMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes); 3314 return StackValue.collectionElement(elementType, resolvedGetCall, resolvedSetCall, this, state); 3315 } 3316 } 3317 3318 @Override 3319 public StackValue visitThrowExpression(@NotNull JetThrowExpression expression, StackValue receiver) { 3320 gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE); 3321 v.athrow(); 3322 return StackValue.none(); 3323 } 3324 3325 @Override 3326 public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) { 3327 DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference()); 3328 if (descriptor instanceof ClassDescriptor) { 3329 return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true); 3330 } 3331 else { 3332 if (descriptor instanceof CallableDescriptor) { 3333 return generateReceiver(descriptor); 3334 } 3335 throw new UnsupportedOperationException("neither this nor receiver"); 3336 } 3337 } 3338 3339 @Override 3340 public StackValue visitTryExpression(@NotNull JetTryExpression expression, StackValue receiver) { 3341 return generateTryExpression(expression, false); 3342 } 3343 3344 public StackValue generateTryExpression(JetTryExpression expression, boolean isStatement) { 3345 /* 3346 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 3347 (or blocks). 3348 */ 3349 JetFinallySection finallyBlock = expression.getFinallyBlock(); 3350 FinallyBlockStackElement finallyBlockStackElement = null; 3351 if (finallyBlock != null) { 3352 finallyBlockStackElement = new FinallyBlockStackElement(expression); 3353 blockStackElements.push(finallyBlockStackElement); 3354 } 3355 3356 JetType jetType = bindingContext.get(EXPRESSION_TYPE, expression); 3357 assert jetType != null; 3358 Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType); 3359 3360 Label tryStart = new Label(); 3361 v.mark(tryStart); 3362 v.nop(); // prevent verify error on empty try 3363 3364 gen(expression.getTryBlock(), expectedAsmType); 3365 3366 int savedValue = -1; 3367 if (!isStatement) { 3368 savedValue = myFrameMap.enterTemp(expectedAsmType); 3369 v.store(savedValue, expectedAsmType); 3370 } 3371 3372 Label tryEnd = new Label(); 3373 v.mark(tryEnd); 3374 3375 //do it before finally block generation 3376 List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd); 3377 3378 Label end = new Label(); 3379 3380 genFinallyBlockOrGoto(finallyBlockStackElement, end); 3381 3382 List<JetCatchClause> clauses = expression.getCatchClauses(); 3383 for (int i = 0, size = clauses.size(); i < size; i++) { 3384 JetCatchClause clause = clauses.get(i); 3385 3386 Label clauseStart = new Label(); 3387 v.mark(clauseStart); 3388 3389 VariableDescriptor descriptor = bindingContext.get(VALUE_PARAMETER, clause.getCatchParameter()); 3390 assert descriptor != null; 3391 Type descriptorType = asmType(descriptor.getType()); 3392 myFrameMap.enter(descriptor, descriptorType); 3393 int index = lookupLocalIndex(descriptor); 3394 v.store(index, descriptorType); 3395 3396 gen(clause.getCatchBody(), expectedAsmType); 3397 3398 if (!isStatement) { 3399 v.store(savedValue, expectedAsmType); 3400 } 3401 3402 myFrameMap.leave(descriptor); 3403 3404 genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null); 3405 3406 generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName()); 3407 } 3408 3409 3410 //for default catch clause 3411 if (finallyBlock != null) { 3412 Label defaultCatchStart = new Label(); 3413 v.mark(defaultCatchStart); 3414 int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE); 3415 v.store(savedException, JAVA_THROWABLE_TYPE); 3416 Label defaultCatchEnd = new Label(); 3417 v.mark(defaultCatchEnd); 3418 3419 //do it before finally block generation 3420 //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter 3421 List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd); 3422 3423 3424 genFinallyBlockOrGoto(finallyBlockStackElement, null); 3425 3426 v.load(savedException, JAVA_THROWABLE_TYPE); 3427 myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE); 3428 3429 v.athrow(); 3430 3431 generateExceptionTable(defaultCatchStart, defaultCatchRegions, null); 3432 } 3433 3434 markLineNumber(expression); 3435 v.mark(end); 3436 3437 if (!isStatement) { 3438 v.load(savedValue, expectedAsmType); 3439 myFrameMap.leaveTemp(expectedAsmType); 3440 } 3441 3442 if (finallyBlock != null) { 3443 blockStackElements.pop(); 3444 } 3445 3446 return StackValue.onStack(expectedAsmType); 3447 } 3448 3449 private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) { 3450 for (int i = 0; i < catchedRegions.size(); i += 2) { 3451 Label startRegion = catchedRegions.get(i); 3452 Label endRegion = catchedRegions.get(i+1); 3453 v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception); 3454 } 3455 } 3456 3457 @NotNull 3458 private static List<Label> getCurrentCatchIntervals( 3459 @Nullable FinallyBlockStackElement finallyBlockStackElement, 3460 @NotNull Label blockStart, 3461 @NotNull Label blockEnd 3462 ) { 3463 List<Label> gapsInBlock = 3464 finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList(); 3465 assert gapsInBlock.size() % 2 == 0; 3466 List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2); 3467 blockRegions.add(blockStart); 3468 blockRegions.addAll(gapsInBlock); 3469 blockRegions.add(blockEnd); 3470 return blockRegions; 3471 } 3472 3473 @Override 3474 public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) { 3475 JetSimpleNameExpression operationSign = expression.getOperationReference(); 3476 IElementType opToken = operationSign.getReferencedNameElementType(); 3477 if (opToken == JetTokens.COLON) { 3478 return gen(expression.getLeft()); 3479 } 3480 else { 3481 JetTypeReference typeReference = expression.getRight(); 3482 JetType rightType = bindingContext.get(TYPE, typeReference); 3483 assert rightType != null; 3484 Type rightTypeAsm = boxType(asmType(rightType)); 3485 JetExpression left = expression.getLeft(); 3486 DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor(); 3487 if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) { 3488 StackValue value = genQualified(receiver, left); 3489 value.put(boxType(value.type), v); 3490 3491 if (opToken != JetTokens.AS_SAFE) { 3492 if (!JvmCodegenUtil.isNullableType(rightType)) { 3493 v.dup(); 3494 Label nonnull = new Label(); 3495 v.ifnonnull(nonnull); 3496 JetType leftType = bindingContext.get(EXPRESSION_TYPE, left); 3497 assert leftType != null; 3498 throwNewException("kotlin/TypeCastException", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(leftType) + 3499 " cannot be cast to " + 3500 DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(rightType)); 3501 v.mark(nonnull); 3502 } 3503 } 3504 else { 3505 v.dup(); 3506 v.instanceOf(rightTypeAsm); 3507 Label ok = new Label(); 3508 v.ifne(ok); 3509 v.pop(); 3510 v.aconst(null); 3511 v.mark(ok); 3512 } 3513 3514 v.checkcast(rightTypeAsm); 3515 return StackValue.onStack(rightTypeAsm); 3516 } 3517 else { 3518 throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor); 3519 } 3520 } 3521 } 3522 3523 @Override 3524 public StackValue visitIsExpression(@NotNull JetIsExpression expression, StackValue receiver) { 3525 StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this); 3526 return generateIsCheck(match, expression.getTypeRef(), expression.isNegated()); 3527 } 3528 3529 private StackValue generateExpressionMatch(StackValue expressionToMatch, JetExpression patternExpression) { 3530 if (expressionToMatch != null) { 3531 Type subjectType = expressionToMatch.type; 3532 expressionToMatch.put(subjectType, v); 3533 JetType condJetType = bindingContext.get(EXPRESSION_TYPE, patternExpression); 3534 Type condType; 3535 if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) { 3536 assert condJetType != null; 3537 condType = asmType(condJetType); 3538 if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) { 3539 subjectType = boxType(subjectType); 3540 expressionToMatch.coerceTo(subjectType, v); 3541 } 3542 } 3543 else { 3544 condType = OBJECT_TYPE; 3545 } 3546 gen(patternExpression, condType); 3547 return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType); 3548 } 3549 else { 3550 return gen(patternExpression); 3551 } 3552 } 3553 3554 private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) { 3555 JetType jetType = bindingContext.get(TYPE, typeReference); 3556 generateInstanceOf(expressionToMatch, jetType, false); 3557 StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); 3558 return negated ? StackValue.not(value) : value; 3559 } 3560 3561 private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) { 3562 expressionToGen.put(OBJECT_TYPE, v); 3563 if (leaveExpressionOnStack) { 3564 v.dup(); 3565 } 3566 Type type = boxType(asmType(jetType)); 3567 if (jetType.isNullable()) { 3568 Label nope = new Label(); 3569 Label end = new Label(); 3570 3571 v.dup(); 3572 v.ifnull(nope); 3573 v.instanceOf(type); 3574 v.goTo(end); 3575 v.mark(nope); 3576 v.pop(); 3577 v.iconst(1); 3578 v.mark(end); 3579 } 3580 else { 3581 v.instanceOf(type); 3582 } 3583 } 3584 3585 @Override 3586 public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) { 3587 return generateWhenExpression(expression, false); 3588 } 3589 3590 public StackValue generateWhenExpression(JetWhenExpression expression, boolean isStatement) { 3591 JetExpression expr = expression.getSubjectExpression(); 3592 Type subjectType = expressionType(expr); 3593 3594 Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression); 3595 3596 if (canSwitchBeUsedIn(expression, subjectType)) { 3597 return generateSwitch(expression, subjectType, resultType, isStatement); 3598 } 3599 3600 int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1; 3601 if (subjectLocal != -1) { 3602 gen(expr, subjectType); 3603 tempVariables.put(expr, StackValue.local(subjectLocal, subjectType)); 3604 v.store(subjectLocal, subjectType); 3605 } 3606 3607 Label end = new Label(); 3608 boolean hasElse = JetPsiUtil.checkWhenExpressionHasSingleElse(expression); 3609 3610 Label nextCondition = null; 3611 for (JetWhenEntry whenEntry : expression.getEntries()) { 3612 if (nextCondition != null) { 3613 v.mark(nextCondition); 3614 } 3615 nextCondition = new Label(); 3616 FrameMap.Mark mark = myFrameMap.mark(); 3617 Label thisEntry = new Label(); 3618 if (!whenEntry.isElse()) { 3619 JetWhenCondition[] conditions = whenEntry.getConditions(); 3620 for (int i = 0; i < conditions.length; i++) { 3621 StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]); 3622 conditionValue.condJump(nextCondition, true, v); 3623 if (i < conditions.length - 1) { 3624 v.goTo(thisEntry); 3625 v.mark(nextCondition); 3626 nextCondition = new Label(); 3627 } 3628 } 3629 } 3630 3631 v.visitLabel(thisEntry); 3632 gen(whenEntry.getExpression(), resultType); 3633 mark.dropTo(); 3634 if (!whenEntry.isElse()) { 3635 v.goTo(end); 3636 } 3637 } 3638 if (!hasElse && nextCondition != null) { 3639 v.mark(nextCondition); 3640 if (!isStatement) { 3641 putUnitInstanceOntoStackForNonExhaustiveWhen(expression); 3642 } 3643 } 3644 3645 markLineNumber(expression); 3646 v.mark(end); 3647 3648 myFrameMap.leaveTemp(subjectType); 3649 tempVariables.remove(expr); 3650 return StackValue.onStack(resultType); 3651 } 3652 3653 private void putUnitInstanceOntoStackForNonExhaustiveWhen(@NotNull JetWhenExpression expression) { 3654 if (Boolean.TRUE.equals(bindingContext.get(EXHAUSTIVE_WHEN, expression))) { 3655 // when() is supposed to be exhaustive 3656 throwNewException("kotlin/NoWhenBranchMatchedException"); 3657 } 3658 else { 3659 // non-exhaustive when() with no else -> Unit must be expected 3660 StackValue.putUnitInstance(v); 3661 } 3662 } 3663 3664 private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition) { 3665 if (condition instanceof JetWhenConditionInRange) { 3666 JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition; 3667 return generateIn(StackValue.local(subjectLocal, subjectType), 3668 conditionInRange.getRangeExpression(), 3669 conditionInRange.getOperationReference()); 3670 } 3671 StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType); 3672 if (condition instanceof JetWhenConditionIsPattern) { 3673 JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition; 3674 return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated()); 3675 } 3676 else if (condition instanceof JetWhenConditionWithExpression) { 3677 JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression(); 3678 return generateExpressionMatch(match, patternExpression); 3679 } 3680 else { 3681 throw new UnsupportedOperationException("unsupported kind of when condition"); 3682 } 3683 } 3684 3685 private StackValue generateSwitch(@NotNull JetWhenExpression expression, @NotNull Type subjectType, @NotNull Type resultType, boolean isStatement) { 3686 JetType subjectJetType = bindingContext.get(EXPRESSION_TYPE, expression.getSubjectExpression()); 3687 assert subjectJetType != null : "Subject expression in when should not be null"; 3688 3689 Map<Integer, Label> transitions = Maps.newTreeMap(); 3690 3691 Label[] entryLabels = new Label[expression.getEntries().size()]; 3692 int entryLabelsCounter = 0; 3693 3694 Label elseLabel = new Label(); 3695 Label endLabel = new Label(); 3696 boolean hasElse = expression.getElseExpression() != null; 3697 3698 for (JetWhenEntry entry : expression.getEntries()) { 3699 Label entryLabel = new Label(); 3700 3701 for (JetWhenCondition condition : entry.getConditions()) { 3702 assert condition instanceof JetWhenConditionWithExpression : "Condition should be instance of JetWhenConditionWithExpression"; 3703 3704 JetExpression conditionExpression = ((JetWhenConditionWithExpression) condition).getExpression(); 3705 assert conditionExpression != null : "Condition expression in when should not be bull"; 3706 3707 CompileTimeConstant constant = getCompileTimeConstant(conditionExpression, bindingContext); 3708 assert doesConstantFitForSwitch(constant) : "Condition should be a constant in when for generating switch-instruction"; 3709 3710 int value = (constant.getValue() instanceof Number) 3711 ? ((Number) constant.getValue()).intValue() 3712 : ((Character) constant.getValue()).charValue(); 3713 3714 if (!transitions.containsKey(value)) { 3715 transitions.put(value, entryLabel); 3716 } 3717 } 3718 3719 if (entry.isElse()) { 3720 elseLabel = entryLabel; 3721 } 3722 3723 entryLabels[entryLabelsCounter++] = entryLabel; 3724 } 3725 3726 gen(expression.getSubjectExpression(), subjectType); 3727 generateSwitchInstructionByTransitionsTable( 3728 transitions, 3729 //if there is no else-entry and it's statement then default --- endLabel 3730 (hasElse || !isStatement) ? elseLabel : endLabel 3731 ); 3732 3733 //resolving entries' labels 3734 int i = 0; 3735 for (JetWhenEntry entry : expression.getEntries()) { 3736 v.visitLabel(entryLabels[i++]); 3737 3738 FrameMap.Mark mark = myFrameMap.mark(); 3739 gen(entry.getExpression(), resultType); 3740 mark.dropTo(); 3741 3742 if (!entry.isElse()) { 3743 v.goTo(endLabel); 3744 } 3745 } 3746 3747 //there is no else-entry but this is not statement, so we should return Unit 3748 if (!hasElse && !isStatement) { 3749 v.visitLabel(elseLabel); 3750 putUnitInstanceOntoStackForNonExhaustiveWhen(expression); 3751 } 3752 3753 markLineNumber(expression); 3754 v.mark(endLabel); 3755 3756 return StackValue.onStack(resultType); 3757 } 3758 3759 private void generateSwitchInstructionByTransitionsTable(@NotNull Map<Integer, Label> transitions, @NotNull Label defaultLabel) { 3760 int[] keys = new int[transitions.size()]; 3761 Label[] labels = new Label[transitions.size()]; 3762 int i = 0; 3763 3764 for (Map.Entry<Integer, Label> transition : transitions.entrySet()) { 3765 keys[i] = transition.getKey(); 3766 labels[i] = transition.getValue(); 3767 3768 i++; 3769 } 3770 3771 int nlabels = keys.length; 3772 int hi = keys[nlabels - 1]; 3773 int lo = keys[0]; 3774 3775 /* 3776 * Heuristic estimation if it's better to use tableswitch or lookupswitch. 3777 * From OpenJDK sources 3778 */ 3779 long table_space_cost = 4 + ((long) hi - lo + 1); // words 3780 long table_time_cost = 3; // comparisons 3781 long lookup_space_cost = 3 + 2 * (long) nlabels; 3782 long lookup_time_cost = nlabels; 3783 3784 boolean useTableSwitch = nlabels > 0 && 3785 table_space_cost + 3 * table_time_cost <= 3786 lookup_space_cost + 3 * lookup_time_cost; 3787 3788 if (!useTableSwitch) { 3789 v.lookupswitch(defaultLabel, keys, labels); 3790 return; 3791 } 3792 3793 Label[] sparseLabels = new Label[hi - lo + 1]; 3794 Arrays.fill(sparseLabels, defaultLabel); 3795 3796 for (i = 0; i < keys.length; i++) { 3797 sparseLabels[keys[i] - lo] = labels[i]; 3798 } 3799 3800 v.tableswitch(lo, hi, defaultLabel, sparseLabels); 3801 } 3802 3803 private static boolean doesConstantFitForSwitch(@Nullable CompileTimeConstant constant) { 3804 return (constant instanceof IntegerValueConstant); 3805 } 3806 3807 private boolean canSwitchBeUsedIn(@NotNull JetWhenExpression expression, @NotNull Type subjectType) { 3808 int typeSort = subjectType.getSort(); 3809 3810 if (typeSort != Type.INT && typeSort != Type.CHAR && typeSort != Type.SHORT && typeSort != Type.BYTE) { 3811 return false; 3812 } 3813 3814 for (JetWhenEntry entry : expression.getEntries()) { 3815 for (JetWhenCondition condition : entry.getConditions()) { 3816 if (!(condition instanceof JetWhenConditionWithExpression)) { 3817 return false; 3818 } 3819 3820 //ensure that expression is constant 3821 JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression(); 3822 3823 assert patternExpression != null : "expression in when should not be null"; 3824 3825 CompileTimeConstant constant = getCompileTimeConstant(patternExpression, bindingContext); 3826 if (!doesConstantFitForSwitch(constant)) { 3827 return false; 3828 } 3829 } 3830 } 3831 3832 return true; 3833 } 3834 3835 private boolean isIntRangeExpr(JetExpression rangeExpression) { 3836 if (rangeExpression instanceof JetBinaryExpression) { 3837 JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression; 3838 if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) { 3839 JetType jetType = bindingContext.get(EXPRESSION_TYPE, rangeExpression); 3840 assert jetType != null; 3841 DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); 3842 return INTEGRAL_RANGES.contains(descriptor); 3843 } 3844 } 3845 return false; 3846 } 3847 3848 private void throwNewException(@NotNull String className) { 3849 throwNewException(className, null); 3850 } 3851 3852 private void throwNewException(@NotNull String className, @Nullable String message) { 3853 v.anew(Type.getObjectType(className)); 3854 v.dup(); 3855 if (message != null) { 3856 v.visitLdcInsn(message); 3857 v.invokespecial(className, "<init>", "(Ljava/lang/String;)V"); 3858 } 3859 else { 3860 v.invokespecial(className, "<init>", "()V"); 3861 } 3862 v.athrow(); 3863 } 3864 3865 private Call makeFakeCall(ReceiverValue initializerAsReceiver) { 3866 JetSimpleNameExpression fake = JetPsiFactory.createSimpleName(state.getProject(), "fake"); 3867 return CallMaker.makeCall(fake, initializerAsReceiver); 3868 } 3869 3870 @Override 3871 public String toString() { 3872 return context.getContextDescriptor().toString(); 3873 } 3874 3875 @NotNull 3876 public FrameMap getFrameMap() { 3877 return myFrameMap; 3878 } 3879 3880 @NotNull 3881 public MethodContext getContext() { 3882 return context; 3883 } 3884 3885 @NotNull 3886 public NameGenerator getInlineNameGenerator() { 3887 NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator(); 3888 Name name = context.getContextDescriptor().getName(); 3889 return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" ); 3890 } 3891 }