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