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