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