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