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.builtins.InlineStrategy; 026 import org.jetbrains.kotlin.builtins.InlineUtil; 027 import org.jetbrains.kotlin.codegen.*; 028 import org.jetbrains.kotlin.codegen.context.CodegenContext; 029 import org.jetbrains.kotlin.codegen.context.FieldOwnerContext; 030 import org.jetbrains.kotlin.codegen.context.MethodContext; 031 import org.jetbrains.kotlin.codegen.context.PackageContext; 032 import org.jetbrains.kotlin.codegen.state.GenerationState; 033 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 034 import org.jetbrains.kotlin.descriptors.*; 035 import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; 036 import org.jetbrains.kotlin.name.ClassId; 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.model.ResolvedCall; 042 import org.jetbrains.kotlin.resolve.jvm.AsmTypes; 043 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 044 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 045 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; 046 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; 047 import org.jetbrains.org.objectweb.asm.Label; 048 import org.jetbrains.org.objectweb.asm.MethodVisitor; 049 import org.jetbrains.org.objectweb.asm.Opcodes; 050 import org.jetbrains.org.objectweb.asm.Type; 051 import org.jetbrains.org.objectweb.asm.commons.Method; 052 import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; 053 import org.jetbrains.org.objectweb.asm.tree.LabelNode; 054 import org.jetbrains.org.objectweb.asm.tree.MethodNode; 055 import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode; 056 057 import java.io.IOException; 058 import java.util.*; 059 060 import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags; 061 import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; 062 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker; 063 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionExpression; 064 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral; 065 066 public class InlineCodegen extends CallGenerator { 067 private final GenerationState state; 068 private final JetTypeMapper typeMapper; 069 070 private final SimpleFunctionDescriptor functionDescriptor; 071 private final JvmMethodSignature jvmSignature; 072 private final JetElement callElement; 073 private final MethodContext context; 074 private final ExpressionCodegen codegen; 075 076 private final boolean asFunctionInline; 077 private final int initialFrameSize; 078 private final boolean isSameModule; 079 080 protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder(); 081 protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>(); 082 083 private final ReifiedTypeInliner reifiedTypeInliner; 084 085 private LambdaInfo activeLambda; 086 087 private final SourceMapper sourceMapper; 088 089 public InlineCodegen( 090 @NotNull ExpressionCodegen codegen, 091 @NotNull GenerationState state, 092 @NotNull SimpleFunctionDescriptor functionDescriptor, 093 @NotNull JetElement callElement, 094 @Nullable ReifiedTypeParameterMappings typeParameterMappings 095 ) { 096 assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor; 097 098 this.state = state; 099 this.typeMapper = state.getTypeMapper(); 100 this.codegen = codegen; 101 this.callElement = callElement; 102 this.functionDescriptor = functionDescriptor.getOriginal(); 103 104 reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings); 105 106 initialFrameSize = codegen.getFrameMap().getCurrentSize(); 107 108 context = (MethodContext) getContext(functionDescriptor, state); 109 jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); 110 111 InlineStrategy inlineStrategy = 112 codegen.getContext().isInlineFunction() ? InlineStrategy.IN_PLACE : functionDescriptor.getInlineStrategy(); 113 this.asFunctionInline = false; 114 115 isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory()); 116 117 sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); 118 } 119 120 @Override 121 public void genCallWithoutAssertions( 122 @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen 123 ) { 124 genCall(callableMethod, null, false, codegen); 125 } 126 127 @Override 128 public void genCallInner(@NotNull CallableMethod callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) { 129 SMAPAndMethodNode nodeAndSmap = null; 130 131 try { 132 nodeAndSmap = createMethodNode(callDefault); 133 endCall(inlineCall(nodeAndSmap)); 134 } 135 catch (CompilationException e) { 136 throw e; 137 } 138 catch (Exception e) { 139 boolean generateNodeText = !(e instanceof InlineException); 140 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor()); 141 throw new CompilationException("Couldn't inline method call '" + 142 functionDescriptor.getName() + 143 "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) + 144 (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""), 145 e, callElement); 146 } 147 148 149 } 150 151 private void endCall(@NotNull InlineResult result) { 152 leaveTemps(); 153 154 codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); 155 156 state.getFactory().removeInlinedClasses(result.getClassesToRemove()); 157 } 158 159 @NotNull 160 private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException { 161 JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); 162 163 Method asmMethod; 164 if (callDefault) { 165 asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context); 166 } 167 else { 168 asmMethod = jvmSignature.getAsmMethod(); 169 } 170 171 SMAPAndMethodNode nodeAndSMAP; 172 if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { 173 ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable( 174 (DeserializedSimpleFunctionDescriptor) functionDescriptor); 175 176 VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state); 177 if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) { 178 /*use facade class*/ 179 containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName()); 180 } 181 nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), 182 asmMethod.getName(), 183 asmMethod.getDescriptor(), 184 containerClassId); 185 186 if (nodeAndSMAP == null) { 187 throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); 188 } 189 } 190 else { 191 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); 192 193 if (element == null || !(element instanceof JetNamedFunction)) { 194 throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); 195 } 196 JetNamedFunction inliningFunction = (JetNamedFunction) element; 197 198 MethodNode node = new MethodNode(InlineCodegenUtil.API, 199 getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), 200 asmMethod.getName(), 201 asmMethod.getDescriptor(), 202 jvmSignature.getGenericsSignature(), 203 null); 204 205 //for maxLocals calculation 206 MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); 207 MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); 208 209 SMAP smap; 210 if (callDefault) { 211 Type ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/); 212 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, 213 (FieldOwnerContext) methodContext.getParentContext(), 214 ownerType.getInternalName()); 215 FunctionCodegen.generateDefaultImplBody( 216 methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, 217 inliningFunction, parentCodegen 218 ); 219 smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); 220 } 221 else { 222 smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false); 223 } 224 225 nodeAndSMAP = new SMAPAndMethodNode(node, smap); 226 maxCalcAdapter.visitMaxs(-1, -1); 227 maxCalcAdapter.visitEnd(); 228 } 229 return nodeAndSMAP; 230 } 231 232 private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) { 233 MethodNode node = nodeAndSmap.getNode(); 234 ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions); 235 generateClosuresBodies(); 236 237 //through generation captured parameters will be added to invocationParamBuilder 238 putClosureParametersOnStack(); 239 240 addInlineMarker(codegen.v, true); 241 242 Parameters parameters = invocationParamBuilder.buildParameters(); 243 244 InliningContext info = new RootInliningContext(expressionMap, 245 state, 246 codegen.getInlineNameGenerator() 247 .subGenerator(functionDescriptor.getName().asString()), 248 codegen.getContext(), 249 callElement, 250 codegen.getParentCodegen().getClassName(), reifiedTypeInliner); 251 252 MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, 253 "Method inlining " + callElement.getText(), 254 createNestedSourceMapper(nodeAndSmap)); //with captured 255 256 LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize); 257 258 259 MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode(); 260 //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain 261 adapter.visitInsn(Opcodes.NOP); 262 263 InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL); 264 result.getReifiedTypeParametersUsages().mergeAll(reificationResult); 265 266 LabelOwner labelOwner = new LabelOwner() { 267 268 final CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor(); 269 270 final boolean isLambda = isFunctionExpression(descriptor) || isFunctionLiteral(descriptor); 271 272 @Override 273 public boolean isMyLabel(@NotNull String name) { 274 if (InlineCodegenUtil.ROOT_LABEL.equals(name)) { 275 return !isLambda; 276 } 277 else { 278 return descriptor.getName().asString().equals(name); 279 } 280 } 281 }; 282 List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null); 283 generateAndInsertFinallyBlocks(adapter, infos); 284 285 adapter.accept(new InliningInstructionAdapter(codegen.v)); 286 287 addInlineMarker(codegen.v, false); 288 289 return result; 290 } 291 292 private void generateClosuresBodies() { 293 for (LambdaInfo info : expressionMap.values()) { 294 info.setNode(generateLambdaBody(info)); 295 } 296 } 297 298 private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) { 299 JetFunctionLiteral declaration = info.getFunctionLiteral(); 300 FunctionDescriptor descriptor = info.getFunctionDescriptor(); 301 302 MethodContext parentContext = codegen.getContext(); 303 304 MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor); 305 306 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor); 307 Method asmMethod = jvmMethodSignature.getAsmMethod(); 308 MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null); 309 310 MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); 311 312 SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true); 313 adapter.visitMaxs(-1, -1); 314 return new SMAPAndMethodNode(methodNode, smap); 315 } 316 317 private SMAP generateMethodBody( 318 @NotNull MethodVisitor adapter, 319 @NotNull FunctionDescriptor descriptor, 320 @NotNull MethodContext context, 321 @NotNull JetDeclarationWithBody declaration, 322 @NotNull JvmMethodSignature jvmMethodSignature, 323 boolean isLambda 324 ) { 325 FakeMemberCodegen parentCodegen = 326 new FakeMemberCodegen(codegen.getParentCodegen(), declaration, 327 (FieldOwnerContext) context.getParentContext(), 328 isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName()); 329 330 FunctionCodegen.generateMethodBody( 331 adapter, descriptor, context, jvmMethodSignature, 332 new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), 333 // Wrapping for preventing marking actual parent codegen as containing reifier markers 334 parentCodegen 335 ); 336 337 return createSMAPWithDefaultMapping(declaration, parentCodegen.getOrCreateSourceMapper().getResultMappings()); 338 } 339 340 private static SMAP createSMAPWithDefaultMapping( 341 @NotNull JetDeclarationWithBody declaration, 342 @NotNull List<FileMapping> mappings 343 ) { 344 PsiFile containingFile = declaration.getContainingFile(); 345 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); 346 assert lineNumbers != null : "Couldn't extract line count in " + containingFile; 347 348 return new SMAP(mappings); 349 } 350 351 private static class FakeMemberCodegen extends MemberCodegen { 352 353 private final MemberCodegen delegate; 354 @NotNull private final String className; 355 356 public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) { 357 super(wrapped, declaration, codegenContext); 358 delegate = wrapped; 359 this.className = className; 360 } 361 362 @Override 363 protected void generateDeclaration() { 364 throw new IllegalStateException(); 365 } 366 367 @Override 368 protected void generateBody() { 369 throw new IllegalStateException(); 370 } 371 372 @Override 373 protected void generateKotlinAnnotation() { 374 throw new IllegalStateException(); 375 } 376 377 @NotNull 378 @Override 379 public NameGenerator getInlineNameGenerator() { 380 return delegate.getInlineNameGenerator(); 381 } 382 383 @NotNull 384 @Override 385 //TODO: obtain name from context 386 public String getClassName() { 387 return className; 388 } 389 } 390 391 @Override 392 public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { 393 putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1); 394 } 395 396 private void putCapturedInLocal( 397 @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex 398 ) { 399 if (!asFunctionInline && Type.VOID_TYPE != type) { 400 //TODO remap only inlinable closure => otherwise we could get a lot of problem 401 boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor); 402 StackValue remappedIndex = couldBeRemapped ? stackValue : null; 403 404 ParameterInfo info; 405 if (capturedParamIndex >= 0) { 406 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); 407 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName()); 408 info.setRemapValue(remappedIndex); 409 } 410 else { 411 info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); 412 } 413 414 putParameterOnStack(info); 415 } 416 } 417 418 /*descriptor is null for captured vars*/ 419 public boolean shouldPutValue( 420 @NotNull Type type, 421 @Nullable StackValue stackValue, 422 @Nullable ValueParameterDescriptor descriptor 423 ) { 424 425 if (stackValue == null) { 426 //default or vararg 427 return true; 428 } 429 430 //remap only inline functions (and maybe non primitives) 431 //TODO - clean asserion and remapping logic 432 if (isPrimitive(type) != isPrimitive(stackValue.type)) { 433 //don't remap boxing/unboxing primitives - lost identity and perfomance 434 return true; 435 } 436 437 if (stackValue instanceof StackValue.Local) { 438 return false; 439 } 440 441 //skip direct capturing fields 442 StackValue receiver = null; 443 if (stackValue instanceof StackValue.Field) { 444 receiver = ((StackValue.Field) stackValue).receiver; 445 } 446 else if (stackValue instanceof StackValue.FieldForSharedVar) { 447 receiver = ((StackValue.Field) ((StackValue.FieldForSharedVar) stackValue).receiver).receiver; 448 } 449 450 if (!(receiver instanceof StackValue.Local)) { 451 return true; 452 } 453 454 //TODO: check type of context 455 return !(codegen.getContext().isInliningLambda() && descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor)); 456 } 457 458 private void putParameterOnStack(ParameterInfo... infos) { 459 int[] index = new int[infos.length]; 460 for (int i = 0; i < infos.length; i++) { 461 ParameterInfo info = infos[i]; 462 if (!info.isSkippedOrRemapped()) { 463 index[i] = codegen.getFrameMap().enterTemp(info.getType()); 464 } 465 else { 466 index[i] = -1; 467 } 468 } 469 470 for (int i = infos.length - 1; i >= 0; i--) { 471 ParameterInfo info = infos[i]; 472 if (!info.isSkippedOrRemapped()) { 473 Type type = info.type; 474 StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v); 475 } 476 } 477 } 478 479 @Override 480 public void putHiddenParams() { 481 List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters(); 482 483 if (!isStaticMethod(functionDescriptor, context)) { 484 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); 485 } 486 487 for (JvmMethodParameterSignature param : valueParameters) { 488 if (param.getKind() == JvmMethodParameterKind.VALUE) { 489 break; 490 } 491 invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); 492 } 493 494 List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured(); 495 putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()])); 496 } 497 498 public void leaveTemps() { 499 FrameMap frameMap = codegen.getFrameMap(); 500 List<ParameterInfo> infos = invocationParamBuilder.listAllParams(); 501 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { 502 ParameterInfo param = iterator.previous(); 503 if (!param.isSkippedOrRemapped()) { 504 frameMap.leaveTemp(param.type); 505 } 506 } 507 } 508 509 public static boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) { 510 //TODO deparenthisise typed 511 JetExpression deparenthesize = JetPsiUtil.deparenthesize(expression); 512 return deparenthesize instanceof JetFunctionLiteralExpression && 513 !InlineUtil.hasNoinlineAnnotation(valueParameterDescriptora); 514 } 515 516 public void rememberClosure(JetExpression expression, Type type) { 517 JetFunctionLiteralExpression lambda = (JetFunctionLiteralExpression) JetPsiUtil.deparenthesize(expression); 518 assert lambda != null : "Couldn't find lambda in " + expression.getText(); 519 520 String labelNameIfPresent = null; 521 PsiElement parent = lambda.getParent(); 522 if (parent instanceof JetLabeledExpression) { 523 labelNameIfPresent = ((JetLabeledExpression) parent).getLabelName(); 524 } 525 LambdaInfo info = new LambdaInfo(lambda, typeMapper, labelNameIfPresent); 526 527 ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); 528 closureInfo.setLambda(info); 529 expressionMap.put(closureInfo.getIndex(), info); 530 } 531 532 private void putClosureParametersOnStack() { 533 for (LambdaInfo next : expressionMap.values()) { 534 activeLambda = next; 535 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this); 536 } 537 activeLambda = null; 538 } 539 540 public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) { 541 if (descriptor instanceof PackageFragmentDescriptor) { 542 return new PackageContext((PackageFragmentDescriptor) descriptor, null, null); 543 } 544 545 CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state); 546 547 if (descriptor instanceof ClassDescriptor) { 548 OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION; 549 return parent.intoClass((ClassDescriptor) descriptor, kind, state); 550 } 551 else if (descriptor instanceof FunctionDescriptor) { 552 return parent.intoFunction((FunctionDescriptor) descriptor); 553 } 554 555 throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor)); 556 } 557 558 private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) { 559 return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; 560 } 561 562 private static String descriptorName(DeclarationDescriptor descriptor) { 563 return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor); 564 } 565 566 @Override 567 public void genValueAndPut( 568 @NotNull ValueParameterDescriptor valueParameterDescriptor, 569 @NotNull JetExpression argumentExpression, 570 @NotNull Type parameterType 571 ) { 572 //TODO deparenthisise 573 if (isInliningClosure(argumentExpression, valueParameterDescriptor)) { 574 rememberClosure(argumentExpression, parameterType); 575 } else { 576 StackValue value = codegen.gen(argumentExpression); 577 putValueIfNeeded(valueParameterDescriptor, parameterType, value); 578 } 579 } 580 581 @Override 582 public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { 583 if (shouldPutValue(parameterType, value, valueParameterDescriptor)) { 584 value.put(parameterType, codegen.v); 585 } 586 afterParameterPut(parameterType, value, valueParameterDescriptor); 587 } 588 589 @Override 590 public void putCapturedValueOnStack( 591 @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex 592 ) { 593 if (shouldPutValue(stackValue.type, stackValue, null)) { 594 stackValue.put(stackValue.type, codegen.v); 595 } 596 putCapturedInLocal(stackValue.type, stackValue, null, paramIndex); 597 } 598 599 600 public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.PointForExternalFinallyBlocks> insertPoints) { 601 if (!codegen.hasFinallyBlocks()) return; 602 603 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints = 604 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>(); 605 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) { 606 extensionPoints.put(insertPoint.beforeIns, insertPoint); 607 } 608 609 DefaultProcessor processor = new DefaultProcessor(intoNode); 610 611 AbstractInsnNode curInstr = intoNode.instructions.getFirst(); 612 while (curInstr != null) { 613 processor.updateCoveringTryBlocks(curInstr, true); 614 615 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); 616 if (extension != null) { 617 Label start = new Label(); 618 Label end = new Label(); 619 620 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); 621 finallyNode.visitLabel(start); 622 623 ExpressionCodegen finallyCodegen = 624 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(), 625 codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); 626 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements()); 627 628 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType); 629 finallyNode.visitLabel(end); 630 631 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method 632 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); 633 634 List<TryCatchBlockNodeWrapper> blocks = processor.getCoveringFromInnermost(); 635 ListIterator<TryCatchBlockNodeWrapper> iterator = blocks.listIterator(blocks.size()); 636 while (iterator.hasPrevious()) { 637 TryCatchBlockNodeWrapper previous = iterator.previous(); 638 LabelNode oldStart = previous.getStartLabel(); 639 TryCatchBlockNode node = previous.getNode(); 640 node.start = (LabelNode) end.info; 641 processor.remapStartLabel(oldStart, previous); 642 643 TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type); 644 processor.addNode(additionalNode); 645 } 646 } 647 648 curInstr = curInstr.getNext(); 649 } 650 651 processor.sortTryCatchBlocks(); 652 Iterable<TryCatchBlockNodeWrapper> nodes = processor.getNonEmptyNodes(); 653 intoNode.tryCatchBlocks.clear(); 654 for (TryCatchBlockNodeWrapper node : nodes) { 655 intoNode.tryCatchBlocks.add(node.getNode()); 656 } 657 } 658 659 private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { 660 return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); 661 } 662 663 }