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