001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.codegen.inline;
018
019 import com.intellij.openapi.vfs.VirtualFile;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.PsiFile;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.backend.common.CodegenUtil;
025 import org.jetbrains.kotlin.codegen.*;
026 import org.jetbrains.kotlin.codegen.context.*;
027 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
028 import org.jetbrains.kotlin.codegen.state.GenerationState;
029 import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
030 import org.jetbrains.kotlin.descriptors.*;
031 import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
032 import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents;
033 import org.jetbrains.kotlin.modules.TargetId;
034 import org.jetbrains.kotlin.name.ClassId;
035 import org.jetbrains.kotlin.name.Name;
036 import org.jetbrains.kotlin.psi.*;
037 import org.jetbrains.kotlin.renderer.DescriptorRenderer;
038 import org.jetbrains.kotlin.resolve.BindingContext;
039 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
040 import org.jetbrains.kotlin.resolve.DescriptorUtils;
041 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
042 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
043 import org.jetbrains.kotlin.resolve.inline.InlineUtil;
044 import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
045 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
046 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
047 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
048 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
049 import org.jetbrains.kotlin.types.expressions.LabelResolver;
050 import org.jetbrains.org.objectweb.asm.Label;
051 import org.jetbrains.org.objectweb.asm.MethodVisitor;
052 import org.jetbrains.org.objectweb.asm.Opcodes;
053 import org.jetbrains.org.objectweb.asm.Type;
054 import org.jetbrains.org.objectweb.asm.commons.Method;
055 import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
056 import org.jetbrains.org.objectweb.asm.tree.InsnList;
057 import org.jetbrains.org.objectweb.asm.tree.LabelNode;
058 import org.jetbrains.org.objectweb.asm.tree.MethodNode;
059
060 import java.io.IOException;
061 import java.util.*;
062
063 import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
064 import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
065 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
066 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant;
067 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
068
069 public class InlineCodegen extends CallGenerator {
070 private final GenerationState state;
071 private final JetTypeMapper typeMapper;
072
073 private final FunctionDescriptor functionDescriptor;
074 private final JvmMethodSignature jvmSignature;
075 private final KtElement callElement;
076 private final MethodContext context;
077 private final ExpressionCodegen codegen;
078
079 private final boolean asFunctionInline;
080 private final int initialFrameSize;
081 private final boolean isSameModule;
082
083 private final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
084 private final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
085
086 private final ReifiedTypeInliner reifiedTypeInliner;
087 @Nullable private final TypeParameterMappings typeParameterMappings;
088 private final boolean isDefaultCompilation;
089
090 private LambdaInfo activeLambda;
091
092 private final SourceMapper sourceMapper;
093
094 public InlineCodegen(
095 @NotNull ExpressionCodegen codegen,
096 @NotNull GenerationState state,
097 @NotNull FunctionDescriptor function,
098 @NotNull KtElement callElement,
099 @Nullable TypeParameterMappings typeParameterMappings,
100 boolean isDefaultCompilation
101 ) {
102 assert InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function) :
103 "InlineCodegen can inline only inline functions and array constructors: " + function;
104 this.isDefaultCompilation = isDefaultCompilation;
105 this.state = state;
106 this.typeMapper = state.getTypeMapper();
107 this.codegen = codegen;
108 this.callElement = callElement;
109 this.functionDescriptor =
110 InlineUtil.isArrayConstructorWithLambda(function)
111 ? FictitiousArrayConstructor.create((ConstructorDescriptor) function)
112 : function.getOriginal();
113 this.typeParameterMappings = typeParameterMappings;
114
115 reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
116
117 initialFrameSize = codegen.getFrameMap().getCurrentSize();
118
119 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
120 context = (MethodContext) getContext(functionDescriptor, state, element != null ? (KtFile) element.getContainingFile() : null);
121 jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
122
123 // TODO: implement AS_FUNCTION inline strategy
124 this.asFunctionInline = false;
125
126 isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
127
128 sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
129
130 if (!(functionDescriptor instanceof FictitiousArrayConstructor)) {
131 reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal());
132 }
133 }
134
135 @Override
136 public void genCallWithoutAssertions(@NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen) {
137 genCall(callableMethod, null, false, codegen);
138 }
139
140 @Override
141 public void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
142 SMAPAndMethodNode nodeAndSmap = null;
143 if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
144 generateStub(resolvedCall, codegen);
145 return;
146 }
147
148 try {
149 nodeAndSmap = createMethodNode(callDefault);
150 endCall(inlineCall(nodeAndSmap));
151 }
152 catch (CompilationException e) {
153 throw e;
154 }
155 catch (Exception e) {
156 boolean generateNodeText = !(e instanceof InlineException);
157 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
158 throw new CompilationException("Couldn't inline method call '" +
159 functionDescriptor.getName() +
160 "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
161 (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
162 e, callElement);
163 }
164 finally {
165 state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
166 }
167 }
168
169 protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
170 leaveTemps();
171 assert resolvedCall != null;
172 String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
173 AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
174 }
175
176 private void endCall(@NotNull InlineResult result) {
177 leaveTemps();
178
179 codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
180
181 state.getFactory().removeClasses(result.getClassesToRemove());
182
183 codegen.markLineNumberAfterInlineIfNeeded();
184 }
185
186 @NotNull
187 private SMAPAndMethodNode createMethodNode(boolean callDefault) throws IOException {
188 Method asmMethod = callDefault
189 ? typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind())
190 : jvmSignature.getAsmMethod();
191
192 SMAPAndMethodNode nodeAndSMAP;
193 if (functionDescriptor instanceof FictitiousArrayConstructor) {
194 nodeAndSMAP = InlineCodegenUtil.getMethodNode(
195 IntrinsicArrayConstructorsKt.getBytecode(),
196 asmMethod.getName(),
197 asmMethod.getDescriptor(),
198 IntrinsicArrayConstructorsKt.getClassId()
199 );
200
201 if (nodeAndSMAP == null) {
202 throw new IllegalStateException("Couldn't obtain array constructor body for " + descriptorName(functionDescriptor));
203 }
204 }
205 else if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
206 JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable(
207 (DeserializedSimpleFunctionDescriptor) functionDescriptor);
208
209 ClassId containerId = containingClasses.getImplClassId();
210 VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId);
211 if (file == null) {
212 throw new IllegalStateException("Couldn't find declaration file for " + containerId);
213 }
214
215 nodeAndSMAP = InlineCodegenUtil.getMethodNode(
216 file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), containingClasses.getFacadeClassId()
217 );
218
219 if (nodeAndSMAP == null) {
220 throw new IllegalStateException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
221 }
222 }
223 else {
224 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
225
226 if (!(element instanceof KtNamedFunction)) {
227 throw new IllegalStateException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
228 }
229 KtNamedFunction inliningFunction = (KtNamedFunction) element;
230
231 MethodNode node = new MethodNode(InlineCodegenUtil.API,
232 getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
233 asmMethod.getName(),
234 asmMethod.getDescriptor(),
235 jvmSignature.getGenericsSignature(),
236 null);
237
238 //for maxLocals calculation
239 MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
240 MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
241
242 SMAP smap;
243 if (callDefault) {
244 Type implementationOwner = typeMapper.mapOwner(functionDescriptor);
245 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
246 (FieldOwnerContext) methodContext.getParentContext(),
247 implementationOwner.getInternalName());
248 FunctionCodegen.generateDefaultImplBody(
249 methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
250 inliningFunction, parentCodegen, asmMethod
251 );
252 smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
253 }
254 else {
255 smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false);
256 }
257
258 nodeAndSMAP = new SMAPAndMethodNode(node, smap);
259 maxCalcAdapter.visitMaxs(-1, -1);
260 maxCalcAdapter.visitEnd();
261 }
262 return nodeAndSMAP;
263 }
264
265 private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
266 MethodNode node = nodeAndSmap.getNode();
267 ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
268 generateClosuresBodies();
269
270 //through generation captured parameters will be added to invocationParamBuilder
271 putClosureParametersOnStack();
272
273 addInlineMarker(codegen.v, true);
274
275 Parameters parameters = invocationParamBuilder.buildParameters();
276
277 InliningContext info = new RootInliningContext(
278 expressionMap, state, codegen.getInlineNameGenerator().subGenerator(jvmSignature.getAsmMethod().getName()),
279 codegen.getContext(), callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings, isDefaultCompilation
280 );
281
282 MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
283 "Method inlining " + callElement.getText(),
284 createNestedSourceMapper(nodeAndSmap), info.getCallSiteInfo()); //with captured
285
286 LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
287
288
289 MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
290 //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
291 adapter.visitInsn(Opcodes.NOP);
292
293 InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
294 result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
295
296 CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
297 final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
298 LabelOwner labelOwner = new LabelOwner() {
299 @Override
300 public boolean isMyLabel(@NotNull String name) {
301 return labels.contains(name);
302 }
303 };
304
305 List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
306 generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index);
307 removeFinallyMarkers(adapter);
308
309 adapter.accept(new InliningInstructionAdapter(codegen.v));
310
311 addInlineMarker(codegen.v, false);
312
313 return result;
314 }
315
316 private InlineCallSiteInfo getInlineCallSiteInfo() {
317 MethodContext context = codegen.getContext();
318 MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
319 while (context instanceof InlineLambdaContext) {
320 CodegenContext closureContext = context.getParentContext();
321 assert closureContext instanceof ClosureContext : "Parent context of inline lambda should be closure context";
322 assert closureContext.getParentContext() instanceof MethodContext : "Closure context should appear in method context";
323 context = (MethodContext) closureContext.getParentContext();
324 assert parentCodegen instanceof FakeMemberCodegen : "Parent codegen of inlined lambda should be FakeMemberCodegen";
325 parentCodegen = ((FakeMemberCodegen) parentCodegen).delegate;
326 }
327
328 JvmMethodSignature signature = typeMapper.mapSignature(context.getFunctionDescriptor(), context.getContextKind());
329 return new InlineCallSiteInfo(parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor());
330 }
331
332 private void generateClosuresBodies() {
333 for (LambdaInfo info : expressionMap.values()) {
334 info.setNode(generateLambdaBody(info));
335 }
336 }
337
338 private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
339 KtExpression declaration = info.getFunctionWithBodyOrCallableReference();
340 FunctionDescriptor descriptor = info.getFunctionDescriptor();
341
342 MethodContext parentContext = codegen.getContext();
343
344 MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor, info.isCrossInline);
345
346 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
347 Method asmMethod = jvmMethodSignature.getAsmMethod();
348 MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
349
350 MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
351
352 SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
353 adapter.visitMaxs(-1, -1);
354 return new SMAPAndMethodNode(methodNode, smap);
355 }
356
357 private SMAP generateMethodBody(
358 @NotNull MethodVisitor adapter,
359 @NotNull FunctionDescriptor descriptor,
360 @NotNull MethodContext context,
361 @NotNull KtExpression expression,
362 @NotNull JvmMethodSignature jvmMethodSignature,
363 boolean isLambda
364 ) {
365 FakeMemberCodegen parentCodegen =
366 new FakeMemberCodegen(codegen.getParentCodegen(), expression,
367 (FieldOwnerContext) context.getParentContext(),
368 isLambda ? codegen.getParentCodegen().getClassName()
369 : typeMapper.mapOwner(descriptor).getInternalName());
370
371 FunctionGenerationStrategy strategy =
372 expression instanceof KtCallableReferenceExpression ?
373 new FunctionReferenceGenerationStrategy(
374 state,
375 descriptor,
376 CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(),
377 codegen.getBindingContext()
378 )) :
379 new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (KtDeclarationWithBody) expression);
380
381 FunctionCodegen.generateMethodBody(
382 adapter, descriptor, context, jvmMethodSignature,
383 strategy,
384 // Wrapping for preventing marking actual parent codegen as containing reifier markers
385 parentCodegen
386 );
387
388 if (isLambda) {
389 codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.getReifiedTypeParametersUsages());
390 }
391
392 return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
393 }
394
395 private static SMAP createSMAPWithDefaultMapping(
396 @NotNull KtExpression declaration,
397 @NotNull List<FileMapping> mappings
398 ) {
399 PsiFile containingFile = declaration.getContainingFile();
400 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
401 assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
402
403 return new SMAP(mappings);
404 }
405
406 private static class FakeMemberCodegen extends MemberCodegen {
407
408 @NotNull final MemberCodegen delegate;
409 @NotNull private final String className;
410
411 public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
412 super(wrapped, declaration, codegenContext);
413 delegate = wrapped;
414 this.className = className;
415 }
416
417 @Override
418 protected void generateDeclaration() {
419 throw new IllegalStateException();
420 }
421
422 @Override
423 protected void generateBody() {
424 throw new IllegalStateException();
425 }
426
427 @Override
428 protected void generateKotlinAnnotation() {
429 throw new IllegalStateException();
430 }
431
432 @NotNull
433 @Override
434 public NameGenerator getInlineNameGenerator() {
435 return delegate.getInlineNameGenerator();
436 }
437
438 @NotNull
439 @Override
440 //TODO: obtain name from context
441 public String getClassName() {
442 return className;
443 }
444 }
445
446 @Override
447 public void afterParameterPut(
448 @NotNull Type type,
449 @Nullable StackValue stackValue,
450 int parameterIndex
451 ) {
452 putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
453 }
454
455 private void putArgumentOrCapturedToLocalVal(
456 @NotNull Type type,
457 @Nullable StackValue stackValue,
458 int capturedParamIndex,
459 int parameterIndex
460 ) {
461 if (!asFunctionInline && Type.VOID_TYPE != type) {
462 //TODO remap only inlinable closure => otherwise we could get a lot of problem
463 boolean couldBeRemapped = !shouldPutValue(type, stackValue);
464 StackValue remappedIndex = couldBeRemapped ? stackValue : null;
465
466 ParameterInfo info;
467 if (capturedParamIndex >= 0) {
468 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
469 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
470 info.setRemapValue(remappedIndex);
471 }
472 else {
473 info = invocationParamBuilder.addNextValueParameter(type, false, remappedIndex, parameterIndex);
474 }
475
476 recordParameterValueInLocalVal(info);
477 }
478 }
479
480 /*descriptor is null for captured vars*/
481 public static boolean shouldPutValue(
482 @NotNull Type type,
483 @Nullable StackValue stackValue
484 ) {
485
486 if (stackValue == null) {
487 //default or vararg
488 return true;
489 }
490
491 //remap only inline functions (and maybe non primitives)
492 //TODO - clean asserion and remapping logic
493 if (isPrimitive(type) != isPrimitive(stackValue.type)) {
494 //don't remap boxing/unboxing primitives - lost identity and perfomance
495 return true;
496 }
497
498 if (stackValue instanceof StackValue.Local) {
499 return false;
500 }
501
502 StackValue field = stackValue;
503 if (stackValue instanceof StackValue.FieldForSharedVar) {
504 field = ((StackValue.FieldForSharedVar) stackValue).receiver;
505 }
506
507 //check that value corresponds to captured inlining parameter
508 if (field instanceof StackValue.Field) {
509 DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
510 //check that variable is inline function parameter
511 return !(varDescriptor instanceof ParameterDescriptor &&
512 InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) &&
513 InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
514 }
515
516 return true;
517 }
518
519 private void recordParameterValueInLocalVal(ParameterInfo... infos) {
520 int[] index = new int[infos.length];
521 for (int i = 0; i < infos.length; i++) {
522 ParameterInfo info = infos[i];
523 if (!info.isSkippedOrRemapped()) {
524 index[i] = codegen.getFrameMap().enterTemp(info.getType());
525 }
526 else {
527 index[i] = -1;
528 }
529 }
530
531 for (int i = infos.length - 1; i >= 0; i--) {
532 ParameterInfo info = infos[i];
533 if (!info.isSkippedOrRemapped()) {
534 Type type = info.type;
535 StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
536 }
537 }
538 }
539
540 @Override
541 public void putHiddenParams() {
542 if ((getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == 0) {
543 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
544 }
545
546 for (JvmMethodParameterSignature param : jvmSignature.getValueParameters()) {
547 if (param.getKind() == JvmMethodParameterKind.VALUE) {
548 break;
549 }
550 invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
551 }
552
553 invocationParamBuilder.markValueParametesStart();
554 List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getReal();
555 recordParameterValueInLocalVal(hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()]));
556 }
557
558 public void leaveTemps() {
559 FrameMap frameMap = codegen.getFrameMap();
560 List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
561 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
562 ParameterInfo param = iterator.previous();
563 if (!param.isSkippedOrRemapped()) {
564 frameMap.leaveTemp(param.type);
565 }
566 }
567 }
568
569 /*lambda or callable reference*/
570 public boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
571 //TODO deparenthisise typed
572 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
573
574 if (deparenthesized instanceof KtCallableReferenceExpression) {
575 // TODO: support inline of property references passed to inlinable function parameters
576 SimpleFunctionDescriptor functionReference = state.getBindingContext().get(BindingContext.FUNCTION, deparenthesized);
577 if (functionReference == null) return false;
578 }
579
580 return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) &&
581 isInlinableParameterExpression(deparenthesized);
582 }
583
584 protected static boolean isInlinableParameterExpression(KtExpression deparenthesized) {
585 return deparenthesized instanceof KtLambdaExpression ||
586 deparenthesized instanceof KtNamedFunction ||
587 deparenthesized instanceof KtCallableReferenceExpression;
588 }
589
590 public void rememberClosure(KtExpression expression, Type type, ValueParameterDescriptor parameter) {
591 KtExpression lambda = KtPsiUtil.deparenthesize(expression);
592 assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
593
594
595 LambdaInfo info = new LambdaInfo(lambda, typeMapper, parameter.isCrossinline());
596
597 ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.getIndex());
598 closureInfo.setLambda(info);
599 expressionMap.put(closureInfo.getIndex(), info);
600 }
601
602 @NotNull
603 protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
604 Set<String> result = new HashSet<String>();
605
606 if (lambdaOrFun != null) {
607 Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun);
608 if (label != null) {
609 result.add(label.asString());
610 }
611 }
612
613 if (!isFunctionLiteral(descriptor)) {
614 if (!descriptor.getName().isSpecial()) {
615 result.add(descriptor.getName().asString());
616 }
617 result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
618 }
619 return result;
620 }
621
622 private void putClosureParametersOnStack() {
623 for (LambdaInfo next : expressionMap.values()) {
624 activeLambda = next;
625 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
626 }
627 activeLambda = null;
628 }
629
630 public static CodegenContext getContext(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile) {
631 if (descriptor instanceof PackageFragmentDescriptor) {
632 return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile);
633 }
634
635 CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile);
636
637 if (descriptor instanceof ScriptDescriptor) {
638 List<ScriptDescriptor> earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter();
639 return parent.intoScript((ScriptDescriptor) descriptor,
640 earlierScripts == null ? Collections.emptyList() : earlierScripts,
641 (ClassDescriptor) descriptor, state.getTypeMapper());
642 }
643 else if (descriptor instanceof ClassDescriptor) {
644 OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
645 return parent.intoClass((ClassDescriptor) descriptor, kind, state);
646 }
647 else if (descriptor instanceof FunctionDescriptor) {
648 return parent.intoFunction((FunctionDescriptor) descriptor);
649 }
650
651 throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
652 }
653
654 private static String descriptorName(DeclarationDescriptor descriptor) {
655 return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
656 }
657
658 @Override
659 public void genValueAndPut(
660 @NotNull ValueParameterDescriptor valueParameterDescriptor,
661 @NotNull KtExpression argumentExpression,
662 @NotNull Type parameterType,
663 int parameterIndex
664 ) {
665 if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
666 rememberClosure(argumentExpression, parameterType, valueParameterDescriptor);
667 }
668 else {
669 StackValue value = codegen.gen(argumentExpression);
670 putValueIfNeeded(parameterType, value, valueParameterDescriptor.getIndex());
671 }
672 }
673
674 @Override
675 public void putValueIfNeeded(
676 @NotNull Type parameterType,
677 @NotNull StackValue value
678 ) {
679 putValueIfNeeded(parameterType, value, -1);
680 }
681
682 private void putValueIfNeeded(
683 @NotNull Type parameterType,
684 @NotNull StackValue value,
685 int index
686 ) {
687 if (shouldPutValue(parameterType, value)) {
688 value.put(parameterType, codegen.v);
689 }
690 afterParameterPut(parameterType, value, index);
691 }
692
693 @Override
694 public void putCapturedValueOnStack(
695 @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
696 ) {
697 if (shouldPutValue(stackValue.type, stackValue)) {
698 stackValue.put(stackValue.type, codegen.v);
699 }
700 putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
701 }
702
703
704 public void generateAndInsertFinallyBlocks(
705 @NotNull MethodNode intoNode,
706 @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
707 int offsetForFinallyLocalVar
708 ) {
709 if (!codegen.hasFinallyBlocks()) return;
710
711 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
712 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
713 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
714 extensionPoints.put(insertPoint.beforeIns, insertPoint);
715 }
716
717 DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);
718
719 int curFinallyDepth = 0;
720 AbstractInsnNode curInstr = intoNode.instructions.getFirst();
721 while (curInstr != null) {
722 processor.processInstruction(curInstr, true);
723 if (InlineCodegenUtil.isFinallyStart(curInstr)) {
724 //TODO depth index calc could be more precise
725 curFinallyDepth = getConstant(curInstr.getPrevious());
726 }
727
728 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
729 if (extension != null) {
730 Label start = new Label();
731
732 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
733 finallyNode.visitLabel(start);
734
735 ExpressionCodegen finallyCodegen =
736 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
737 codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
738 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDepth);
739
740 FrameMap frameMap = finallyCodegen.getFrameMap();
741 FrameMap.Mark mark = frameMap.mark();
742 int marker = -1;
743 Set<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getCurrentIntervals();
744 for (LocalVarNodeWrapper interval : intervals) {
745 marker = Math.max(interval.getNode().index + 1, marker);
746 }
747 while (frameMap.getCurrentSize() < Math.max(processor.getNextFreeLocalIndex(), offsetForFinallyLocalVar + marker)) {
748 frameMap.enterTemp(Type.INT_TYPE);
749 }
750
751 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.getLabel());
752
753 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
754 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
755
756 SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd);
757 processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true);
758
759 //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
760
761 mark.dropTo();
762 }
763
764 curInstr = curInstr.getNext();
765 }
766
767 processor.substituteTryBlockNodes(intoNode);
768
769 //processor.substituteLocalVarTable(intoNode);
770 }
771
772 public void removeFinallyMarkers(@NotNull MethodNode intoNode) {
773 if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
774
775 InsnList instructions = intoNode.instructions;
776 AbstractInsnNode curInstr = instructions.getFirst();
777 while (curInstr != null) {
778 if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
779 AbstractInsnNode marker = curInstr;
780 //just to assert
781 getConstant(marker.getPrevious());
782 curInstr = curInstr.getNext();
783 instructions.remove(marker.getPrevious());
784 instructions.remove(marker);
785 continue;
786 }
787 curInstr = curInstr.getNext();
788 }
789 }
790
791 private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
792 return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
793 }
794
795 private void reportIncrementalInfo(
796 @NotNull FunctionDescriptor sourceDescriptor,
797 @NotNull FunctionDescriptor targetDescriptor
798 ) {
799 IncrementalCompilationComponents incrementalCompilationComponents = state.getIncrementalCompilationComponents();
800 TargetId targetId = state.getTargetId();
801
802 if (incrementalCompilationComponents == null || targetId == null) return;
803
804 IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId);
805 String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, typeMapper, incrementalCache);
806 String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor);
807 incrementalCache.registerInline(classFilePath, jvmSignature.toString(), sourceFilePath);
808 }
809
810 @Override
811 public void reorderArgumentsIfNeeded(
812 @NotNull List<ArgumentAndDeclIndex> actualArgsWithDeclIndex, @NotNull List<? extends Type> valueParameterTypes
813 ) {
814
815 }
816 }