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 com.intellij.util.ArrayUtil;
023 import kotlin.jvm.functions.Function0;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.kotlin.backend.common.CodegenUtil;
027 import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
028 import org.jetbrains.kotlin.codegen.*;
029 import org.jetbrains.kotlin.codegen.context.*;
030 import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
031 import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
032 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
033 import org.jetbrains.kotlin.codegen.state.GenerationState;
034 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
035 import org.jetbrains.kotlin.descriptors.*;
036 import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
037 import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
038 import org.jetbrains.kotlin.name.ClassId;
039 import org.jetbrains.kotlin.name.Name;
040 import org.jetbrains.kotlin.psi.*;
041 import org.jetbrains.kotlin.resolve.BindingContext;
042 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
043 import org.jetbrains.kotlin.resolve.DescriptorUtils;
044 import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor;
045 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
046 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
047 import org.jetbrains.kotlin.resolve.inline.InlineUtil;
048 import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
049 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
050 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
051 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
052 import org.jetbrains.kotlin.resolve.scopes.MemberScope;
053 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
054 import org.jetbrains.kotlin.types.KotlinType;
055 import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
056 import org.jetbrains.kotlin.types.expressions.LabelResolver;
057 import org.jetbrains.org.objectweb.asm.Label;
058 import org.jetbrains.org.objectweb.asm.MethodVisitor;
059 import org.jetbrains.org.objectweb.asm.Opcodes;
060 import org.jetbrains.org.objectweb.asm.Type;
061 import org.jetbrains.org.objectweb.asm.commons.Method;
062 import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
063 import org.jetbrains.org.objectweb.asm.tree.InsnList;
064 import org.jetbrains.org.objectweb.asm.tree.LabelNode;
065 import org.jetbrains.org.objectweb.asm.tree.MethodNode;
066
067 import java.io.IOException;
068 import java.util.*;
069
070 import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
071 import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
072 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*;
073 import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isInlineOnly;
074 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
075
076 public class InlineCodegen extends CallGenerator {
077 private final GenerationState state;
078 private final KotlinTypeMapper typeMapper;
079
080 private final FunctionDescriptor functionDescriptor;
081 private final JvmMethodSignature jvmSignature;
082 private final KtElement callElement;
083 private final MethodContext context;
084 private final ExpressionCodegen codegen;
085
086 private final boolean asFunctionInline;
087 private final int initialFrameSize;
088 private final boolean isSameModule;
089
090 private final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
091 private final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
092
093 private final ReifiedTypeInliner reifiedTypeInliner;
094
095 @Nullable
096 private final TypeParameterMappings typeParameterMappings;
097
098 private LambdaInfo activeLambda;
099
100 private final SourceMapper sourceMapper;
101
102 private Runnable delayedHiddenWriting;
103
104 public InlineCodegen(
105 @NotNull ExpressionCodegen codegen,
106 @NotNull GenerationState state,
107 @NotNull FunctionDescriptor function,
108 @NotNull KtElement callElement,
109 @Nullable TypeParameterMappings typeParameterMappings
110 ) {
111 assert InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function) :
112 "InlineCodegen can inline only inline functions and array constructors: " + function;
113 this.state = state;
114 this.typeMapper = state.getTypeMapper();
115 this.codegen = codegen;
116 this.callElement = callElement;
117 this.functionDescriptor =
118 InlineUtil.isArrayConstructorWithLambda(function)
119 ? FictitiousArrayConstructor.create((ConstructorDescriptor) function)
120 : function.getOriginal();
121 this.typeParameterMappings = typeParameterMappings;
122
123 reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
124
125 initialFrameSize = codegen.getFrameMap().getCurrentSize();
126
127 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
128 context = (MethodContext) getContext(functionDescriptor, state, element != null ? (KtFile) element.getContainingFile() : null);
129 jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, context.getContextKind());
130
131 // TODO: implement AS_FUNCTION inline strategy
132 this.asFunctionInline = false;
133
134 isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
135
136 sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
137
138 if (!(functionDescriptor instanceof FictitiousArrayConstructor)) {
139 reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal(), jvmSignature, state);
140 String functionOrAccessorName = typeMapper.mapAsmMethod(function).getName();
141 //track changes for property accessor and @JvmName inline functions/property accessors
142 if(!functionOrAccessorName.equals(functionDescriptor.getName().asString())) {
143 MemberScope scope = getMemberScope(functionDescriptor);
144 if (scope != null) {
145 //Fake lookup to track track changes for property accessors and @JvmName functions/property accessors
146 scope.getContributedFunctions(Name.identifier(functionOrAccessorName), new KotlinLookupLocation(callElement));
147 }
148 }
149 }
150 }
151
152 @Nullable
153 private static MemberScope getMemberScope(@NotNull FunctionDescriptor functionOrAccessor) {
154 CallableMemberDescriptor callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor);
155 DeclarationDescriptor classOrPackageFragment = callableMemberDescriptor.getContainingDeclaration();
156 if (classOrPackageFragment instanceof ClassDescriptor) {
157 return ((ClassDescriptor) classOrPackageFragment).getUnsubstitutedMemberScope();
158 }
159 else if (classOrPackageFragment instanceof PackageFragmentDescriptor) {
160 return ((PackageFragmentDescriptor) classOrPackageFragment).getMemberScope();
161 }
162 return null;
163 }
164
165 @Override
166 public void genCallInner(
167 @NotNull Callable callableMethod,
168 @Nullable ResolvedCall<?> resolvedCall,
169 boolean callDefault,
170 @NotNull ExpressionCodegen codegen
171 ) {
172 if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
173 generateStub(resolvedCall, codegen);
174 return;
175 }
176
177 SMAPAndMethodNode nodeAndSmap = null;
178 try {
179 nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall);
180 endCall(inlineCall(nodeAndSmap));
181 }
182 catch (CompilationException e) {
183 throw e;
184 }
185 catch (InlineException e) {
186 throw throwCompilationException(nodeAndSmap, e, false);
187 }
188 catch (Exception e) {
189 throw throwCompilationException(nodeAndSmap, e, true);
190 }
191 finally {
192 state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
193 }
194 }
195
196 @NotNull
197 private CompilationException throwCompilationException(
198 @Nullable SMAPAndMethodNode nodeAndSmap, @NotNull Exception e, boolean generateNodeText
199 ) {
200 CallableMemberDescriptor contextDescriptor = codegen.getContext().getContextDescriptor();
201 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor);
202 MethodNode node = nodeAndSmap != null ? nodeAndSmap.getNode() : null;
203 throw new CompilationException(
204 "Couldn't inline method call '" + functionDescriptor.getName() + "' into\n" +
205 contextDescriptor + "\n" +
206 (element != null ? element.getText() : "<no source>") +
207 (generateNodeText ? ("\nCause: " + InlineCodegenUtil.getNodeText(node)) : ""),
208 e, callElement
209 );
210 }
211
212 private void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
213 leaveTemps();
214 assert resolvedCall != null;
215 String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
216 AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
217 }
218
219 private void endCall(@NotNull InlineResult result) {
220 leaveTemps();
221
222 codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
223
224 state.getFactory().removeClasses(result.calcClassesToRemove());
225
226 codegen.markLineNumberAfterInlineIfNeeded();
227 }
228
229 @NotNull
230 static SMAPAndMethodNode createMethodNode(
231 @NotNull final FunctionDescriptor functionDescriptor,
232 @NotNull JvmMethodSignature jvmSignature,
233 @NotNull ExpressionCodegen codegen,
234 @NotNull CodegenContext context,
235 boolean callDefault,
236 @Nullable ResolvedCall<?> resolvedCall
237 ) {
238 if (InlineCodegenUtil.isSpecialEnumMethod(functionDescriptor)) {
239 assert resolvedCall != null : "Resolved call for " + functionDescriptor + " should be not null";
240 Map<TypeParameterDescriptor, KotlinType> arguments = resolvedCall.getTypeArguments();
241 assert arguments.size() == 1 : "Resolved call for " + functionDescriptor + " should have 1 type argument";
242
243 MethodNode node =
244 InlineCodegenUtil.createSpecialEnumMethodBody(
245 codegen,
246 functionDescriptor.getName().asString(),
247 arguments.keySet().iterator().next().getDefaultType(),
248 codegen.getState().getTypeMapper()
249 );
250 return new SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1));
251 }
252 else if (CoroutineCodegenUtilKt.isBuiltInSuspendCoroutineOrReturnInJvm(functionDescriptor)) {
253 return new SMAPAndMethodNode(
254 CoroutineCodegenUtilKt.createMethodNodeForSuspendCoroutineOrReturn(
255 functionDescriptor, codegen.getState().getTypeMapper()
256 ),
257 SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
258 );
259 }
260
261 final GenerationState state = codegen.getState();
262 final Method asmMethod =
263 callDefault
264 ? state.getTypeMapper().mapDefaultMethod(functionDescriptor, context.getContextKind())
265 : jvmSignature.getAsmMethod();
266
267 MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod);
268 final CallableMemberDescriptor directMember = getDirectMemberAndCallableFromObject(functionDescriptor);
269 if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(directMember instanceof DeserializedCallableMemberDescriptor)) {
270 return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod);
271 }
272
273 SMAPAndMethodNode resultInCache = InlineCacheKt.getOrPut(
274 state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() {
275 @Override
276 public SMAPAndMethodNode invoke() {
277 SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod);
278 if (result == null) {
279 throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor);
280 }
281 return result;
282 }
283 }
284 );
285
286 return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.getNode()));
287 }
288
289 @NotNull
290 private static CallableMemberDescriptor getDirectMemberAndCallableFromObject(@NotNull FunctionDescriptor functionDescriptor) {
291 CallableMemberDescriptor directMember = JvmCodegenUtil.getDirectMember(functionDescriptor);
292 if (directMember instanceof ImportedFromObjectCallableDescriptor) {
293 return ((ImportedFromObjectCallableDescriptor) directMember).getCallableFromObject();
294 }
295 return directMember;
296 }
297
298 @NotNull
299 private static MethodNode cloneMethodNode(@NotNull MethodNode methodNode) {
300 methodNode.instructions.resetLabels();
301 MethodNode result = new MethodNode(
302 API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature,
303 ArrayUtil.toStringArray(methodNode.exceptions)
304 );
305 methodNode.accept(result);
306 return result;
307 }
308
309 @Nullable
310 private static SMAPAndMethodNode doCreateMethodNodeFromCompiled(
311 @NotNull CallableMemberDescriptor callableDescriptor,
312 @NotNull final GenerationState state,
313 @NotNull Method asmMethod
314 ) {
315 if (isBuiltInArrayIntrinsic(callableDescriptor)) {
316 ClassId classId = IntrinsicArrayConstructorsKt.getClassId();
317 byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0<byte[]>() {
318 @Override
319 public byte[] invoke() {
320 return IntrinsicArrayConstructorsKt.getBytecode();
321 }
322 });
323
324 return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state);
325 }
326
327 assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor;
328
329 KotlinTypeMapper.ContainingClassesInfo containingClasses =
330 state.getTypeMapper().getContainingClassesForDeserializedCallable((DeserializedCallableMemberDescriptor) callableDescriptor);
331
332 final ClassId containerId = containingClasses.getImplClassId();
333
334 byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), containerId, new Function0<byte[]>() {
335 @Override
336 public byte[] invoke() {
337 VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId);
338 if (file == null) {
339 throw new IllegalStateException("Couldn't find declaration file for " + containerId);
340 }
341 try {
342 return file.contentsToByteArray();
343 }
344 catch (IOException e) {
345 throw new RuntimeException(e);
346 }
347 }
348 });
349
350
351 return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId, state);
352 }
353
354 @NotNull
355 private static SMAPAndMethodNode doCreateMethodNodeFromSource(
356 @NotNull FunctionDescriptor callableDescriptor,
357 @NotNull JvmMethodSignature jvmSignature,
358 @NotNull ExpressionCodegen codegen,
359 @NotNull CodegenContext context,
360 boolean callDefault,
361 @NotNull GenerationState state,
362 @NotNull Method asmMethod
363 ) {
364 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor);
365
366 if (!(element instanceof KtNamedFunction || element instanceof KtPropertyAccessor)) {
367 throw new IllegalStateException("Couldn't find declaration for function " + callableDescriptor);
368 }
369 KtDeclarationWithBody inliningFunction = (KtDeclarationWithBody) element;
370
371 MethodNode node = new MethodNode(
372 InlineCodegenUtil.API,
373 getMethodAsmFlags(callableDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0),
374 asmMethod.getName(),
375 asmMethod.getDescriptor(),
376 null, null
377 );
378
379 //for maxLocals calculation
380 MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
381 CodegenContext parentContext = context.getParentContext();
382 assert parentContext != null : "Context has no parent: " + context;
383 MethodContext methodContext = parentContext.intoFunction(callableDescriptor);
384
385 SMAP smap;
386 if (callDefault) {
387 Type implementationOwner = state.getTypeMapper().mapImplementationOwner(callableDescriptor);
388 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(
389 codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(),
390 implementationOwner.getInternalName()
391 );
392 if (!(element instanceof KtNamedFunction)) {
393 throw new IllegalStateException("Propertiy accessors with default parameters not supported " + callableDescriptor);
394 }
395 FunctionCodegen.generateDefaultImplBody(
396 methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
397 (KtNamedFunction) inliningFunction, parentCodegen, asmMethod
398 );
399 smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
400 }
401 else {
402 smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction, jvmSignature, codegen,
403 null);
404 }
405 maxCalcAdapter.visitMaxs(-1, -1);
406 maxCalcAdapter.visitEnd();
407
408 return new SMAPAndMethodNode(node, smap);
409 }
410
411 private static boolean isBuiltInArrayIntrinsic(@NotNull CallableMemberDescriptor callableDescriptor) {
412 if (callableDescriptor instanceof FictitiousArrayConstructor) return true;
413 String name = callableDescriptor.getName().asString();
414 return (name.equals("arrayOf") || name.equals("emptyArray")) &&
415 callableDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment;
416 }
417
418 @NotNull
419 private InlineResult inlineCall(@NotNull SMAPAndMethodNode nodeAndSmap) {
420 assert delayedHiddenWriting == null : "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'";
421 DefaultSourceMapper defaultSourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
422 defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber()));
423 MethodNode node = nodeAndSmap.getNode();
424 ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
425 generateClosuresBodies();
426
427 //through generation captured parameters will be added to invocationParamBuilder
428 putClosureParametersOnStack();
429
430 addInlineMarker(codegen.v, true);
431
432 Parameters parameters = invocationParamBuilder.buildParameters();
433
434 InliningContext info = new RootInliningContext(
435 expressionMap, state, codegen.getInlineNameGenerator().subGenerator(jvmSignature.getAsmMethod().getName()),
436 callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings
437 );
438
439 MethodInliner inliner = new MethodInliner(
440 node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
441 "Method inlining " + callElement.getText(),
442 createNestedSourceMapper(nodeAndSmap, sourceMapper), info.getCallSiteInfo(),
443 isInlineOnly(functionDescriptor) ? new InlineOnlySmapSkipper(codegen) : null
444 ); //with captured
445
446 LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
447
448 MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
449 //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
450 adapter.visitInsn(Opcodes.NOP);
451
452 InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
453 result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
454
455 CallableMemberDescriptor descriptor = getLabelOwnerDescriptor(codegen.getContext());
456 final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
457 LabelOwner labelOwner = new LabelOwner() {
458 @Override
459 public boolean isMyLabel(@NotNull String name) {
460 return labels.contains(name);
461 }
462 };
463
464 List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
465 generateAndInsertFinallyBlocks(
466 adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index
467 );
468 removeStaticInitializationTrigger(adapter);
469 removeFinallyMarkers(adapter);
470
471 adapter.accept(new MethodBodyVisitor(codegen.v));
472
473 addInlineMarker(codegen.v, false);
474
475 defaultSourceMapper.setCallSiteMarker(null);
476
477 return result;
478 }
479
480 @NotNull
481 private static CallableMemberDescriptor getLabelOwnerDescriptor(@NotNull MethodContext context) {
482 if (context.getParentContext() instanceof ClosureContext &&
483 ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor() != null) {
484 //noinspection ConstantConditions
485 return ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor();
486 }
487
488 return context.getContextDescriptor();
489 }
490
491 private static void removeStaticInitializationTrigger(@NotNull MethodNode methodNode) {
492 InsnList insnList = methodNode.instructions;
493 AbstractInsnNode insn = insnList.getFirst();
494 while (insn != null) {
495 if (MultifileClassPartCodegen.isStaticInitTrigger(insn)) {
496 AbstractInsnNode clinitTriggerCall = insn;
497 insn = insn.getNext();
498 insnList.remove(clinitTriggerCall);
499 }
500 else {
501 insn = insn.getNext();
502 }
503 }
504 }
505
506 @NotNull
507 private InlineCallSiteInfo getInlineCallSiteInfo() {
508 MethodContext context = codegen.getContext();
509 MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
510 while (context instanceof InlineLambdaContext) {
511 CodegenContext closureContext = context.getParentContext();
512 assert closureContext instanceof ClosureContext : "Parent context of inline lambda should be closure context";
513 assert closureContext.getParentContext() instanceof MethodContext : "Closure context should appear in method context";
514 context = (MethodContext) closureContext.getParentContext();
515 assert parentCodegen instanceof FakeMemberCodegen : "Parent codegen of inlined lambda should be FakeMemberCodegen";
516 parentCodegen = ((FakeMemberCodegen) parentCodegen).delegate;
517 }
518
519 JvmMethodSignature signature = typeMapper.mapSignatureSkipGeneric(context.getFunctionDescriptor(), context.getContextKind());
520 return new InlineCallSiteInfo(
521 parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor()
522 );
523 }
524
525 private void generateClosuresBodies() {
526 for (LambdaInfo info : expressionMap.values()) {
527 info.setNode(generateLambdaBody(info));
528 }
529 }
530
531 @NotNull
532 private SMAPAndMethodNode generateLambdaBody(@NotNull LambdaInfo info) {
533 KtExpression declaration = info.getFunctionWithBodyOrCallableReference();
534 FunctionDescriptor descriptor = info.getFunctionDescriptor();
535
536 ClassContext closureContext = info.isPropertyReference()
537 ? codegen.getContext().intoAnonymousClass(info.getClassDescriptor(), codegen, OwnerKind.IMPLEMENTATION)
538 : codegen.getContext().intoClosure(descriptor, codegen, typeMapper);
539 MethodContext context = closureContext.intoInlinedLambda(descriptor, info.isCrossInline, info.isPropertyReference());
540
541 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(descriptor);
542 Method asmMethod = jvmMethodSignature.getAsmMethod();
543 MethodNode methodNode = new MethodNode(
544 InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind(), state),
545 asmMethod.getName(), asmMethod.getDescriptor(), null, null
546 );
547
548 MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
549
550 SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, codegen, info);
551 adapter.visitMaxs(-1, -1);
552 return new SMAPAndMethodNode(methodNode, smap);
553 }
554
555 @NotNull
556 private static SMAP generateMethodBody(
557 @NotNull MethodVisitor adapter,
558 @NotNull FunctionDescriptor descriptor,
559 @NotNull MethodContext context,
560 @NotNull KtExpression expression,
561 @NotNull JvmMethodSignature jvmMethodSignature,
562 @NotNull ExpressionCodegen codegen,
563 @Nullable LambdaInfo lambdaInfo
564 ) {
565 boolean isLambda = lambdaInfo != null;
566 GenerationState state = codegen.getState();
567
568 // Wrapping for preventing marking actual parent codegen as containing reified markers
569 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(
570 codegen.getParentCodegen(), expression, (FieldOwnerContext) context.getParentContext(),
571 isLambda ? codegen.getParentCodegen().getClassName()
572 : state.getTypeMapper().mapImplementationOwner(descriptor).getInternalName()
573 );
574
575 FunctionGenerationStrategy strategy;
576 if (expression instanceof KtCallableReferenceExpression) {
577 KtCallableReferenceExpression callableReferenceExpression = (KtCallableReferenceExpression) expression;
578 KtExpression receiverExpression = callableReferenceExpression.getReceiverExpression();
579 Type receiverType =
580 receiverExpression != null && codegen.getBindingContext().getType(receiverExpression) != null
581 ? codegen.getState().getTypeMapper().mapType(codegen.getBindingContext().getType(receiverExpression))
582 : null;
583
584 if (isLambda && lambdaInfo.isPropertyReference()) {
585 Type asmType = state.getTypeMapper().mapClass(lambdaInfo.getClassDescriptor());
586 PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo();
587 strategy = new PropertyReferenceCodegen.PropertyReferenceGenerationStrategy(
588 true, info.getGetFunction(), info.getTarget(), asmType, receiverType, lambdaInfo.expression, state, true);
589 }
590 else {
591 strategy = new FunctionReferenceGenerationStrategy(
592 state,
593 descriptor,
594 CallUtilKt
595 .getResolvedCallWithAssert(callableReferenceExpression.getCallableReference(), codegen.getBindingContext()),
596 receiverType,
597 null,
598 true
599 );
600 }
601 }
602 else if (expression instanceof KtFunctionLiteral) {
603 strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
604 }
605 else if (descriptor.isSuspend() && expression instanceof KtFunction) {
606 strategy =
607 new SuspendFunctionGenerationStrategy(
608 state,
609 CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(descriptor),
610 (KtFunction) expression
611 );
612 }
613 else {
614 strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
615 }
616
617 FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen);
618
619 if (isLambda) {
620 codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.getReifiedTypeParametersUsages());
621 }
622
623 return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
624 }
625
626 private static SMAP createSMAPWithDefaultMapping(
627 @NotNull KtExpression declaration,
628 @NotNull List<FileMapping> mappings
629 ) {
630 PsiFile containingFile = declaration.getContainingFile();
631 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
632 assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
633
634 return new SMAP(mappings);
635 }
636
637 private static class FakeMemberCodegen extends MemberCodegen {
638 private final MemberCodegen delegate;
639 private final String className;
640
641 @SuppressWarnings("unchecked")
642 public FakeMemberCodegen(
643 @NotNull MemberCodegen wrapped,
644 @NotNull KtElement declaration,
645 @NotNull FieldOwnerContext codegenContext,
646 @NotNull String className
647 ) {
648 super(wrapped, declaration, codegenContext);
649 this.delegate = wrapped;
650 this.className = className;
651 }
652
653 @Override
654 protected void generateDeclaration() {
655 throw new IllegalStateException();
656 }
657
658 @Override
659 protected void generateBody() {
660 throw new IllegalStateException();
661 }
662
663 @Override
664 protected void generateKotlinMetadataAnnotation() {
665 throw new IllegalStateException();
666 }
667
668 @NotNull
669 @Override
670 public NameGenerator getInlineNameGenerator() {
671 return delegate.getInlineNameGenerator();
672 }
673
674 @NotNull
675 @Override
676 //TODO: obtain name from context
677 public String getClassName() {
678 return className;
679 }
680 }
681
682 @Override
683 public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, int parameterIndex) {
684 putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
685 }
686
687 private void putArgumentOrCapturedToLocalVal(
688 @NotNull Type type,
689 @Nullable StackValue stackValue,
690 int capturedParamIndex,
691 int parameterIndex
692 ) {
693 if (!asFunctionInline && Type.VOID_TYPE != type) {
694 //TODO remap only inlinable closure => otherwise we could get a lot of problem
695 boolean couldBeRemapped = !shouldPutValue(type, stackValue);
696 StackValue remappedValue = couldBeRemapped ? stackValue : null;
697
698 ParameterInfo info;
699 if (capturedParamIndex >= 0) {
700 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
701 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName(), false);
702 info.setRemapValue(remappedValue);
703 }
704 else {
705 info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex);
706 }
707
708 recordParameterValueInLocalVal(false, info);
709 }
710 }
711
712 /*descriptor is null for captured vars*/
713 private static boolean shouldPutValue(@NotNull Type type, @Nullable StackValue stackValue) {
714 if (stackValue == null) {
715 //default or vararg
716 return true;
717 }
718
719 //remap only inline functions (and maybe non primitives)
720 //TODO - clean asserion and remapping logic
721 if (isPrimitive(type) != isPrimitive(stackValue.type)) {
722 //don't remap boxing/unboxing primitives - lost identity and perfomance
723 return true;
724 }
725
726 if (stackValue instanceof StackValue.Local) {
727 return false;
728 }
729
730 StackValue field = stackValue;
731 if (stackValue instanceof StackValue.FieldForSharedVar) {
732 field = ((StackValue.FieldForSharedVar) stackValue).receiver;
733 }
734
735 //check that value corresponds to captured inlining parameter
736 if (field instanceof StackValue.Field) {
737 DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
738 //check that variable is inline function parameter
739 return !(varDescriptor instanceof ParameterDescriptor &&
740 InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) &&
741 InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
742 }
743
744 return true;
745 }
746
747 private Runnable recordParameterValueInLocalVal(boolean delayedWritingToLocals, @NotNull final ParameterInfo... infos) {
748 final int[] index = new int[infos.length];
749 for (int i = 0; i < infos.length; i++) {
750 ParameterInfo info = infos[i];
751 if (!info.isSkippedOrRemapped()) {
752 index[i] = codegen.getFrameMap().enterTemp(info.getType());
753 }
754 else {
755 index[i] = -1;
756 }
757 }
758
759 Runnable runnable = new Runnable() {
760 @Override
761 public void run() {
762 for (int i = infos.length - 1; i >= 0; i--) {
763 ParameterInfo info = infos[i];
764 if (!info.isSkippedOrRemapped()) {
765 Type type = info.type;
766 StackValue.Local local = StackValue.local(index[i], type);
767 local.store(StackValue.onStack(type), codegen.v);
768 if (info instanceof CapturedParamInfo) {
769 info.setRemapValue(local);
770 ((CapturedParamInfo) info).setSynthetic(true);
771 }
772 }
773 }
774 }
775 };
776
777 if (delayedWritingToLocals) return runnable;
778 runnable.run();
779 return null;
780 }
781
782 @Override
783 public void processAndPutHiddenParameters(boolean justProcess) {
784 if ((getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) & Opcodes.ACC_STATIC) == 0) {
785 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false);
786 }
787
788 for (JvmMethodParameterSignature param : jvmSignature.getValueParameters()) {
789 if (param.getKind() == JvmMethodParameterKind.VALUE) {
790 break;
791 }
792 invocationParamBuilder.addNextParameter(param.getAsmType(), false);
793 }
794
795 invocationParamBuilder.markValueParametersStart();
796 List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getParameters();
797
798 delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()]));
799 }
800
801 private void leaveTemps() {
802 List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
803 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
804 ParameterInfo param = iterator.previous();
805 if (!param.isSkippedOrRemapped() || CapturedParamInfo.isSynthetic(param)) {
806 codegen.getFrameMap().leaveTemp(param.type);
807 }
808 }
809 }
810
811 /*lambda or callable reference*/
812 private static boolean isInliningParameter(@NotNull KtExpression expression, @NotNull ValueParameterDescriptor valueParameterDescriptor) {
813 //TODO deparenthisise typed
814 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
815
816 return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) &&
817 isInlinableParameterExpression(deparenthesized);
818 }
819
820 private static boolean isInlinableParameterExpression(@Nullable KtExpression deparenthesized) {
821 return deparenthesized instanceof KtLambdaExpression ||
822 deparenthesized instanceof KtNamedFunction ||
823 deparenthesized instanceof KtCallableReferenceExpression;
824 }
825
826 private LambdaInfo rememberClosure(@NotNull KtExpression expression, @NotNull Type type, @NotNull ValueParameterDescriptor parameter) {
827 KtExpression lambda = KtPsiUtil.deparenthesize(expression);
828 assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
829
830 LambdaInfo info =
831 new LambdaInfo(lambda, typeMapper, parameter.isCrossinline(), getBoundCallableReferenceReceiver(expression) != null);
832
833 ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.getIndex());
834 closureInfo.setLambda(info);
835 expressionMap.put(closureInfo.getIndex(), info);
836 return info;
837 }
838
839 @NotNull
840 public static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
841 Set<String> result = new HashSet<String>();
842
843 if (lambdaOrFun != null) {
844 Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun);
845 if (label != null) {
846 result.add(label.asString());
847 }
848 }
849
850 if (!isFunctionLiteral(descriptor)) {
851 if (!descriptor.getName().isSpecial()) {
852 result.add(descriptor.getName().asString());
853 }
854 result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
855 }
856 return result;
857 }
858
859 private void putClosureParametersOnStack() {
860 for (LambdaInfo next : expressionMap.values()) {
861 //closure parameters for bounded callable references are generated inplace
862 if (next.isBoundCallableReference()) continue;
863 putClosureParametersOnStack(next, null);
864 }
865 }
866
867 private void putClosureParametersOnStack(@NotNull LambdaInfo next, @Nullable StackValue functionReferenceReceiver) {
868 activeLambda = next;
869 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this, functionReferenceReceiver);
870 activeLambda = null;
871 }
872
873 @NotNull
874 public static CodegenContext getContext(
875 @NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile
876 ) {
877 if (descriptor instanceof PackageFragmentDescriptor) {
878 return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile);
879 }
880
881 DeclarationDescriptor container = descriptor.getContainingDeclaration();
882 assert container != null : "No container for descriptor: " + descriptor;
883 CodegenContext parent = getContext(container, state, sourceFile);
884
885 if (descriptor instanceof ScriptDescriptor) {
886 List<ScriptDescriptor> earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter();
887 return parent.intoScript(
888 (ScriptDescriptor) descriptor,
889 earlierScripts == null ? Collections.emptyList() : earlierScripts,
890 (ClassDescriptor) descriptor, state.getTypeMapper()
891 );
892 }
893 else if (descriptor instanceof ClassDescriptor) {
894 OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
895 return parent.intoClass((ClassDescriptor) descriptor, kind, state);
896 }
897 else if (descriptor instanceof FunctionDescriptor) {
898 return parent.intoFunction((FunctionDescriptor) descriptor);
899 }
900
901 throw new IllegalStateException("Couldn't build context for " + descriptor);
902 }
903
904 @Override
905 public void genValueAndPut(
906 @NotNull ValueParameterDescriptor valueParameterDescriptor,
907 @NotNull KtExpression argumentExpression,
908 @NotNull Type parameterType,
909 int parameterIndex
910 ) {
911 if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
912 LambdaInfo lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor);
913
914 KtExpression receiver = getBoundCallableReferenceReceiver(argumentExpression);
915 if (receiver != null) {
916 putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver));
917 }
918 }
919 else {
920 StackValue value = codegen.gen(argumentExpression);
921 putValueIfNeeded(parameterType, value, valueParameterDescriptor.getIndex());
922 }
923 }
924
925 private KtExpression getBoundCallableReferenceReceiver(
926 @NotNull KtExpression argumentExpression
927 ) {
928 KtExpression deparenthesized = KtPsiUtil.deparenthesize(argumentExpression);
929 if (deparenthesized instanceof KtCallableReferenceExpression) {
930 KtExpression receiverExpression = ((KtCallableReferenceExpression) deparenthesized).getReceiverExpression();
931 if (receiverExpression != null) {
932 DoubleColonLHS lhs = state.getBindingContext().get(BindingContext.DOUBLE_COLON_LHS, receiverExpression);
933 if (lhs instanceof DoubleColonLHS.Expression) return receiverExpression;
934 }
935 }
936 return null;
937 }
938
939 @Override
940 public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value) {
941 putValueIfNeeded(parameterType, value, -1);
942 }
943
944 private void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, int index) {
945 if (shouldPutValue(parameterType, value)) {
946 value.put(parameterType, codegen.v);
947 }
948 afterParameterPut(parameterType, value, index);
949 }
950
951 @Override
952 public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
953 if (shouldPutValue(stackValue.type, stackValue)) {
954 stackValue.put(stackValue.type, codegen.v);
955 }
956 putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
957 }
958
959 private void generateAndInsertFinallyBlocks(
960 @NotNull MethodNode intoNode,
961 @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
962 int offsetForFinallyLocalVar
963 ) {
964 if (!codegen.hasFinallyBlocks()) return;
965
966 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
967 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
968 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
969 extensionPoints.put(insertPoint.beforeIns, insertPoint);
970 }
971
972 DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);
973
974 int curFinallyDepth = 0;
975 AbstractInsnNode curInstr = intoNode.instructions.getFirst();
976 while (curInstr != null) {
977 processor.processInstruction(curInstr, true);
978 if (InlineCodegenUtil.isFinallyStart(curInstr)) {
979 //TODO depth index calc could be more precise
980 curFinallyDepth = getConstant(curInstr.getPrevious());
981 }
982
983 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
984 if (extension != null) {
985 Label start = new Label();
986
987 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
988 finallyNode.visitLabel(start);
989
990 ExpressionCodegen finallyCodegen =
991 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
992 codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
993 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDepth);
994
995 FrameMap frameMap = finallyCodegen.getFrameMap();
996 FrameMap.Mark mark = frameMap.mark();
997 int marker = -1;
998 Set<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getCurrentIntervals();
999 for (LocalVarNodeWrapper interval : intervals) {
1000 marker = Math.max(interval.getNode().index + 1, marker);
1001 }
1002 while (frameMap.getCurrentSize() < Math.max(processor.getNextFreeLocalIndex(), offsetForFinallyLocalVar + marker)) {
1003 frameMap.enterTemp(Type.INT_TYPE);
1004 }
1005
1006 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.getLabel());
1007
1008 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
1009 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
1010
1011 SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd);
1012 processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true);
1013
1014 //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
1015
1016 mark.dropTo();
1017 }
1018
1019 curInstr = curInstr.getNext();
1020 }
1021
1022 processor.substituteTryBlockNodes(intoNode);
1023
1024 //processor.substituteLocalVarTable(intoNode);
1025 }
1026
1027 private void removeFinallyMarkers(@NotNull MethodNode intoNode) {
1028 if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
1029
1030 InsnList instructions = intoNode.instructions;
1031 AbstractInsnNode curInstr = instructions.getFirst();
1032 while (curInstr != null) {
1033 if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
1034 AbstractInsnNode marker = curInstr;
1035 //just to assert
1036 getConstant(marker.getPrevious());
1037 curInstr = curInstr.getNext();
1038 instructions.remove(marker.getPrevious());
1039 instructions.remove(marker);
1040 continue;
1041 }
1042 curInstr = curInstr.getNext();
1043 }
1044 }
1045
1046 @NotNull
1047 public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) {
1048 return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
1049 }
1050
1051 static void reportIncrementalInfo(
1052 @NotNull FunctionDescriptor sourceDescriptor,
1053 @NotNull FunctionDescriptor targetDescriptor,
1054 @NotNull JvmMethodSignature jvmSignature,
1055 @NotNull GenerationState state
1056 ) {
1057 IncrementalCache incrementalCache = state.getIncrementalCacheForThisTarget();
1058 if (incrementalCache == null) return;
1059 String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, state.getTypeMapper(), incrementalCache);
1060 String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor);
1061 Method method = jvmSignature.getAsmMethod();
1062 incrementalCache.registerInline(classFilePath, method.getName() + method.getDescriptor(), sourceFilePath);
1063 }
1064
1065 @Override
1066 public void reorderArgumentsIfNeeded(
1067 @NotNull List<ArgumentAndDeclIndex> actualArgsWithDeclIndex, @NotNull List<? extends Type> valueParameterTypes
1068 ) {
1069 }
1070
1071 @Override
1072 public void putHiddenParamsIntoLocals() {
1073 assert delayedHiddenWriting != null : "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals";
1074 delayedHiddenWriting.run();
1075 delayedHiddenWriting = null;
1076 }
1077 }