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