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