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