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