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