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