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 }