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