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