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.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.binding.CodegenBinding.CLASS_FOR_SCRIPT; 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.resolve.DescriptorUtils.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().removeInlinedClasses(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.instructions); 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); 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 return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings()); 358 } 359 360 private static SMAP createSMAPWithDefaultMapping( 361 @NotNull KtExpression declaration, 362 @NotNull List<FileMapping> mappings 363 ) { 364 PsiFile containingFile = declaration.getContainingFile(); 365 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); 366 assert lineNumbers != null : "Couldn't extract line count in " + containingFile; 367 368 return new SMAP(mappings); 369 } 370 371 private static class FakeMemberCodegen extends MemberCodegen { 372 373 private final MemberCodegen delegate; 374 @NotNull private final String className; 375 376 public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) { 377 super(wrapped, declaration, codegenContext); 378 delegate = wrapped; 379 this.className = className; 380 } 381 382 @Override 383 protected void generateDeclaration() { 384 throw new IllegalStateException(); 385 } 386 387 @Override 388 protected void generateBody() { 389 throw new IllegalStateException(); 390 } 391 392 @Override 393 protected void generateKotlinAnnotation() { 394 throw new IllegalStateException(); 395 } 396 397 @NotNull 398 @Override 399 public NameGenerator getInlineNameGenerator() { 400 return delegate.getInlineNameGenerator(); 401 } 402 403 @NotNull 404 @Override 405 //TODO: obtain name from context 406 public String getClassName() { 407 return className; 408 } 409 } 410 411 @Override 412 public void afterParameterPut( 413 @NotNull Type type, 414 @Nullable StackValue stackValue, 415 @Nullable ValueParameterDescriptor valueParameterDescriptor, 416 int parameterIndex 417 ) { 418 putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex); 419 } 420 421 private void putArgumentOrCapturedToLocalVal( 422 @NotNull Type type, 423 @Nullable StackValue stackValue, 424 int capturedParamIndex, 425 int parameterIndex 426 ) { 427 if (!asFunctionInline && Type.VOID_TYPE != type) { 428 //TODO remap only inlinable closure => otherwise we could get a lot of problem 429 boolean couldBeRemapped = !shouldPutValue(type, stackValue); 430 StackValue remappedIndex = couldBeRemapped ? stackValue : null; 431 432 ParameterInfo info; 433 if (capturedParamIndex >= 0) { 434 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); 435 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName()); 436 info.setRemapValue(remappedIndex); 437 } 438 else { 439 info = invocationParamBuilder.addNextValueParameter(type, false, remappedIndex, parameterIndex); 440 } 441 442 recordParameterValueInLocalVal(info); 443 } 444 } 445 446 /*descriptor is null for captured vars*/ 447 public static boolean shouldPutValue( 448 @NotNull Type type, 449 @Nullable StackValue stackValue 450 ) { 451 452 if (stackValue == null) { 453 //default or vararg 454 return true; 455 } 456 457 //remap only inline functions (and maybe non primitives) 458 //TODO - clean asserion and remapping logic 459 if (isPrimitive(type) != isPrimitive(stackValue.type)) { 460 //don't remap boxing/unboxing primitives - lost identity and perfomance 461 return true; 462 } 463 464 if (stackValue instanceof StackValue.Local) { 465 return false; 466 } 467 468 StackValue field = stackValue; 469 if (stackValue instanceof StackValue.FieldForSharedVar) { 470 field = ((StackValue.FieldForSharedVar) stackValue).receiver; 471 } 472 473 //check that value corresponds to captured inlining parameter 474 if (field instanceof StackValue.Field) { 475 DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor; 476 //check that variable is inline function parameter 477 return !(varDescriptor instanceof ParameterDescriptor && 478 InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) && 479 InlineUtil.isInline(varDescriptor.getContainingDeclaration())); 480 } 481 482 return true; 483 } 484 485 private void recordParameterValueInLocalVal(ParameterInfo... infos) { 486 int[] index = new int[infos.length]; 487 for (int i = 0; i < infos.length; i++) { 488 ParameterInfo info = infos[i]; 489 if (!info.isSkippedOrRemapped()) { 490 index[i] = codegen.getFrameMap().enterTemp(info.getType()); 491 } 492 else { 493 index[i] = -1; 494 } 495 } 496 497 for (int i = infos.length - 1; i >= 0; i--) { 498 ParameterInfo info = infos[i]; 499 if (!info.isSkippedOrRemapped()) { 500 Type type = info.type; 501 StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v); 502 } 503 } 504 } 505 506 @Override 507 public void putHiddenParams() { 508 List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters(); 509 510 if (!isStaticMethod(functionDescriptor, context)) { 511 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); 512 } 513 514 for (JvmMethodParameterSignature param : valueParameters) { 515 if (param.getKind() == JvmMethodParameterKind.VALUE) { 516 break; 517 } 518 invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); 519 } 520 521 invocationParamBuilder.markValueParametesStart(); 522 List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getReal(); 523 recordParameterValueInLocalVal(hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()])); 524 } 525 526 public void leaveTemps() { 527 FrameMap frameMap = codegen.getFrameMap(); 528 List<ParameterInfo> infos = invocationParamBuilder.listAllParams(); 529 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { 530 ParameterInfo param = iterator.previous(); 531 if (!param.isSkippedOrRemapped()) { 532 frameMap.leaveTemp(param.type); 533 } 534 } 535 } 536 537 /*lambda or callable reference*/ 538 public static boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) { 539 //TODO deparenthisise typed 540 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression); 541 return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && 542 isInlinableParameterExpression(deparenthesized); 543 } 544 545 protected static boolean isInlinableParameterExpression(KtExpression deparenthesized) { 546 return deparenthesized instanceof KtFunctionLiteralExpression || 547 deparenthesized instanceof KtNamedFunction || 548 deparenthesized instanceof KtCallableReferenceExpression; 549 } 550 551 public void rememberClosure(KtExpression expression, Type type, int parameterIndex) { 552 KtExpression lambda = KtPsiUtil.deparenthesize(expression); 553 assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); 554 555 LambdaInfo info = new LambdaInfo(lambda, typeMapper); 556 557 ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameterIndex); 558 closureInfo.setLambda(info); 559 expressionMap.put(closureInfo.getIndex(), info); 560 } 561 562 @NotNull 563 protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) { 564 Set<String> result = new HashSet<String>(); 565 566 if (lambdaOrFun != null) { 567 Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun); 568 if (label != null) { 569 result.add(label.asString()); 570 } 571 } 572 573 if (!isFunctionLiteral(descriptor)) { 574 if (!descriptor.getName().isSpecial()) { 575 result.add(descriptor.getName().asString()); 576 } 577 result.add(InlineCodegenUtil.FIRST_FUN_LABEL); 578 } 579 return result; 580 } 581 582 private void putClosureParametersOnStack() { 583 for (LambdaInfo next : expressionMap.values()) { 584 activeLambda = next; 585 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this); 586 } 587 activeLambda = null; 588 } 589 590 public static CodegenContext getContext(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile) { 591 if (descriptor instanceof PackageFragmentDescriptor) { 592 return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile); 593 } 594 595 CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile); 596 597 if (descriptor instanceof ClassDescriptor) { 598 OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION; 599 return parent.intoClass((ClassDescriptor) descriptor, kind, state); 600 } 601 else if (descriptor instanceof ScriptDescriptor) { 602 ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor); 603 assert classDescriptorForScript != null : "Can't find class for script: " + descriptor; 604 List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter(); 605 return parent.intoScript((ScriptDescriptor) descriptor, 606 earlierScripts == null ? Collections.emptyList() : earlierScripts, 607 classDescriptorForScript); 608 } 609 else if (descriptor instanceof FunctionDescriptor) { 610 return parent.intoFunction((FunctionDescriptor) descriptor); 611 } 612 613 throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor)); 614 } 615 616 private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) { 617 return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; 618 } 619 620 private static String descriptorName(DeclarationDescriptor descriptor) { 621 return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor); 622 } 623 624 @Override 625 public void genValueAndPut( 626 @NotNull ValueParameterDescriptor valueParameterDescriptor, 627 @NotNull KtExpression argumentExpression, 628 @NotNull Type parameterType, 629 int parameterIndex 630 ) { 631 if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { 632 rememberClosure(argumentExpression, parameterType, valueParameterDescriptor.getIndex()); 633 } 634 else { 635 StackValue value = codegen.gen(argumentExpression); 636 putValueIfNeeded(valueParameterDescriptor, parameterType, value, valueParameterDescriptor.getIndex()); 637 } 638 } 639 640 @Override 641 public void putValueIfNeeded( 642 @Nullable ValueParameterDescriptor valueParameterDescriptor, 643 @NotNull Type parameterType, 644 @NotNull StackValue value 645 ) { 646 putValueIfNeeded(valueParameterDescriptor, parameterType, value, -1); 647 } 648 649 private void putValueIfNeeded( 650 @Nullable ValueParameterDescriptor valueParameterDescriptor, 651 @NotNull Type parameterType, 652 @NotNull StackValue value, 653 int index 654 ) { 655 if (shouldPutValue(parameterType, value)) { 656 value.put(parameterType, codegen.v); 657 } 658 afterParameterPut(parameterType, value, valueParameterDescriptor, index); 659 } 660 661 @Override 662 public void putCapturedValueOnStack( 663 @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex 664 ) { 665 if (shouldPutValue(stackValue.type, stackValue)) { 666 stackValue.put(stackValue.type, codegen.v); 667 } 668 putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex); 669 } 670 671 672 public void generateAndInsertFinallyBlocks( 673 @NotNull MethodNode intoNode, 674 @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints, 675 int offsetForFinallyLocalVar 676 ) { 677 if (!codegen.hasFinallyBlocks()) return; 678 679 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints = 680 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>(); 681 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) { 682 extensionPoints.put(insertPoint.beforeIns, insertPoint); 683 } 684 685 DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); 686 687 int curFinallyDepth = 0; 688 AbstractInsnNode curInstr = intoNode.instructions.getFirst(); 689 while (curInstr != null) { 690 processor.processInstruction(curInstr, true); 691 if (InlineCodegenUtil.isFinallyStart(curInstr)) { 692 //TODO depth index calc could be more precise 693 curFinallyDepth = getConstant(curInstr.getPrevious()); 694 } 695 696 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); 697 if (extension != null) { 698 Label start = new Label(); 699 700 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); 701 finallyNode.visitLabel(start); 702 703 ExpressionCodegen finallyCodegen = 704 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(), 705 codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); 706 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDepth); 707 708 FrameMap frameMap = finallyCodegen.getFrameMap(); 709 FrameMap.Mark mark = frameMap.mark(); 710 int marker = -1; 711 Set<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getCurrentIntervals(); 712 for (LocalVarNodeWrapper interval : intervals) { 713 marker = Math.max(interval.getNode().index + 1, marker); 714 } 715 while (frameMap.getCurrentSize() < Math.max(processor.getNextFreeLocalIndex(), offsetForFinallyLocalVar + marker)) { 716 frameMap.enterTemp(Type.INT_TYPE); 717 } 718 719 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.getLabel()); 720 721 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method 722 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); 723 724 SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd); 725 processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true); 726 727 //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy); 728 729 mark.dropTo(); 730 } 731 732 curInstr = curInstr.getNext(); 733 } 734 735 processor.substituteTryBlockNodes(intoNode); 736 737 //processor.substituteLocalVarTable(intoNode); 738 } 739 740 public void removeFinallyMarkers(@NotNull MethodNode intoNode) { 741 if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return; 742 743 InsnList instructions = intoNode.instructions; 744 AbstractInsnNode curInstr = instructions.getFirst(); 745 while (curInstr != null) { 746 if (InlineCodegenUtil.isFinallyMarker(curInstr)) { 747 AbstractInsnNode marker = curInstr; 748 //just to assert 749 getConstant(marker.getPrevious()); 750 curInstr = curInstr.getNext(); 751 instructions.remove(marker.getPrevious()); 752 instructions.remove(marker); 753 continue; 754 } 755 curInstr = curInstr.getNext(); 756 } 757 } 758 759 private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { 760 return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); 761 } 762 763 private void reportIncrementalInfo( 764 @NotNull FunctionDescriptor sourceDescriptor, 765 @NotNull FunctionDescriptor targetDescriptor 766 ) { 767 IncrementalCompilationComponents incrementalCompilationComponents = state.getIncrementalCompilationComponents(); 768 TargetId targetId = state.getTargetId(); 769 770 if (incrementalCompilationComponents == null || targetId == null) return; 771 772 IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId); 773 String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, typeMapper, incrementalCache); 774 String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor); 775 incrementalCache.registerInline(classFilePath, jvmSignature.toString(), sourceFilePath); 776 } 777 778 @Override 779 public void reorderArgumentsIfNeeded( 780 @NotNull List<? extends ArgumentAndDeclIndex> actualArgsWithDeclIndex, @NotNull List<? extends Type> valueParameterTypes 781 ) { 782 783 } 784 }