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