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