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