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