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