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.PackageClassUtils; 034 import org.jetbrains.kotlin.name.ClassId; 035 import org.jetbrains.kotlin.psi.*; 036 import org.jetbrains.kotlin.renderer.DescriptorRenderer; 037 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 038 import org.jetbrains.kotlin.resolve.DescriptorUtils; 039 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 040 import org.jetbrains.kotlin.resolve.inline.InlineStrategy; 041 import org.jetbrains.kotlin.resolve.inline.InlineUtil; 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 056 import java.io.IOException; 057 import java.util.*; 058 059 import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags; 060 import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; 061 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT; 062 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker; 063 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral; 064 import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert; 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 InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + 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 // TODO: implement AS_FUNCTION inline strategy 112 InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor); 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 Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) { 129 SMAPAndMethodNode nodeAndSmap = null; 130 if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) { 131 generateStub(resolvedCall, codegen); 132 return; 133 } 134 135 try { 136 nodeAndSmap = createMethodNode(callDefault); 137 endCall(inlineCall(nodeAndSmap)); 138 } 139 catch (CompilationException e) { 140 throw e; 141 } 142 catch (Exception e) { 143 boolean generateNodeText = !(e instanceof InlineException); 144 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor()); 145 throw new CompilationException("Couldn't inline method call '" + 146 functionDescriptor.getName() + 147 "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) + 148 (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""), 149 e, callElement); 150 } 151 finally { 152 state.getInlineCycleReporter().exitFromInliningOf(resolvedCall); 153 } 154 } 155 156 protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) { 157 leaveTemps(); 158 assert resolvedCall != null; 159 String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText(); 160 AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message); 161 } 162 163 private void endCall(@NotNull InlineResult result) { 164 leaveTemps(); 165 166 codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); 167 168 state.getFactory().removeInlinedClasses(result.getClassesToRemove()); 169 170 codegen.markLineNumberAfterInlineIfNeeded(); 171 } 172 173 @NotNull 174 private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException { 175 JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); 176 177 Method asmMethod; 178 if (callDefault) { 179 asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context); 180 } 181 else { 182 asmMethod = jvmSignature.getAsmMethod(); 183 } 184 185 SMAPAndMethodNode nodeAndSMAP; 186 if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { 187 ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable( 188 (DeserializedSimpleFunctionDescriptor) functionDescriptor); 189 190 VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state); 191 if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) { 192 /*use facade class*/ 193 containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName()); 194 } 195 nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), 196 asmMethod.getName(), 197 asmMethod.getDescriptor(), 198 containerClassId); 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 JetNamedFunction)) { 208 throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); 209 } 210 JetNamedFunction inliningFunction = (JetNamedFunction) 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 ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/); 226 FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, 227 (FieldOwnerContext) methodContext.getParentContext(), 228 ownerType.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.totalSize() + 1).value).index); 291 292 adapter.accept(new InliningInstructionAdapter(codegen.v)); 293 294 addInlineMarker(codegen.v, false); 295 296 return result; 297 } 298 299 private void generateClosuresBodies() { 300 for (LambdaInfo info : expressionMap.values()) { 301 info.setNode(generateLambdaBody(info)); 302 } 303 } 304 305 private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) { 306 JetExpression declaration = info.getFunctionWithBodyOrCallableReference(); 307 FunctionDescriptor descriptor = info.getFunctionDescriptor(); 308 309 MethodContext parentContext = codegen.getContext(); 310 311 MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor); 312 313 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor); 314 Method asmMethod = jvmMethodSignature.getAsmMethod(); 315 MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null); 316 317 MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); 318 319 SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true); 320 adapter.visitMaxs(-1, -1); 321 return new SMAPAndMethodNode(methodNode, smap); 322 } 323 324 private SMAP generateMethodBody( 325 @NotNull MethodVisitor adapter, 326 @NotNull FunctionDescriptor descriptor, 327 @NotNull MethodContext context, 328 @NotNull JetExpression expression, 329 @NotNull JvmMethodSignature jvmMethodSignature, 330 boolean isLambda 331 ) { 332 FakeMemberCodegen parentCodegen = 333 new FakeMemberCodegen(codegen.getParentCodegen(), expression, 334 (FieldOwnerContext) context.getParentContext(), 335 isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName()); 336 337 FunctionGenerationStrategy strategy = 338 expression instanceof JetCallableReferenceExpression ? 339 new FunctionReferenceGenerationStrategy( 340 state, 341 descriptor, 342 getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(), 343 codegen.getBindingContext() 344 )) : 345 new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression); 346 347 FunctionCodegen.generateMethodBody( 348 adapter, descriptor, context, jvmMethodSignature, 349 strategy, 350 // Wrapping for preventing marking actual parent codegen as containing reifier markers 351 parentCodegen 352 ); 353 354 return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings()); 355 } 356 357 private static SMAP createSMAPWithDefaultMapping( 358 @NotNull JetExpression declaration, 359 @NotNull List<FileMapping> mappings 360 ) { 361 PsiFile containingFile = declaration.getContainingFile(); 362 Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); 363 assert lineNumbers != null : "Couldn't extract line count in " + containingFile; 364 365 return new SMAP(mappings); 366 } 367 368 private static class FakeMemberCodegen extends MemberCodegen { 369 370 private final MemberCodegen delegate; 371 @NotNull private final String className; 372 373 public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) { 374 super(wrapped, declaration, codegenContext); 375 delegate = wrapped; 376 this.className = className; 377 } 378 379 @Override 380 protected void generateDeclaration() { 381 throw new IllegalStateException(); 382 } 383 384 @Override 385 protected void generateBody() { 386 throw new IllegalStateException(); 387 } 388 389 @Override 390 protected void generateKotlinAnnotation() { 391 throw new IllegalStateException(); 392 } 393 394 @NotNull 395 @Override 396 public NameGenerator getInlineNameGenerator() { 397 return delegate.getInlineNameGenerator(); 398 } 399 400 @NotNull 401 @Override 402 //TODO: obtain name from context 403 public String getClassName() { 404 return className; 405 } 406 } 407 408 @Override 409 public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { 410 putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1); 411 } 412 413 private void putCapturedInLocal( 414 @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex 415 ) { 416 if (!asFunctionInline && Type.VOID_TYPE != type) { 417 //TODO remap only inlinable closure => otherwise we could get a lot of problem 418 boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor); 419 StackValue remappedIndex = couldBeRemapped ? stackValue : null; 420 421 ParameterInfo info; 422 if (capturedParamIndex >= 0) { 423 CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); 424 info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName()); 425 info.setRemapValue(remappedIndex); 426 } 427 else { 428 info = invocationParamBuilder.addNextParameter(type, false, remappedIndex); 429 } 430 431 putParameterOnStack(info); 432 } 433 } 434 435 /*descriptor is null for captured vars*/ 436 public boolean shouldPutValue( 437 @NotNull Type type, 438 @Nullable StackValue stackValue, 439 @Nullable ValueParameterDescriptor descriptor 440 ) { 441 442 if (stackValue == null) { 443 //default or vararg 444 return true; 445 } 446 447 //remap only inline functions (and maybe non primitives) 448 //TODO - clean asserion and remapping logic 449 if (isPrimitive(type) != isPrimitive(stackValue.type)) { 450 //don't remap boxing/unboxing primitives - lost identity and perfomance 451 return true; 452 } 453 454 if (stackValue instanceof StackValue.Local) { 455 return false; 456 } 457 458 StackValue field = stackValue; 459 if (stackValue instanceof StackValue.FieldForSharedVar) { 460 field = ((StackValue.FieldForSharedVar) stackValue).receiver; 461 } 462 463 //check that value corresponds to captured inlining parameter 464 if (field instanceof StackValue.Field) { 465 DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor; 466 //check that variable is inline function parameter 467 return !(varDescriptor instanceof ParameterDescriptor && 468 InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) && 469 InlineUtil.isInline(varDescriptor.getContainingDeclaration())); 470 } 471 472 return true; 473 } 474 475 private void putParameterOnStack(ParameterInfo... infos) { 476 int[] index = new int[infos.length]; 477 for (int i = 0; i < infos.length; i++) { 478 ParameterInfo info = infos[i]; 479 if (!info.isSkippedOrRemapped()) { 480 index[i] = codegen.getFrameMap().enterTemp(info.getType()); 481 } 482 else { 483 index[i] = -1; 484 } 485 } 486 487 for (int i = infos.length - 1; i >= 0; i--) { 488 ParameterInfo info = infos[i]; 489 if (!info.isSkippedOrRemapped()) { 490 Type type = info.type; 491 StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v); 492 } 493 } 494 } 495 496 @Override 497 public void putHiddenParams() { 498 List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters(); 499 500 if (!isStaticMethod(functionDescriptor, context)) { 501 invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null); 502 } 503 504 for (JvmMethodParameterSignature param : valueParameters) { 505 if (param.getKind() == JvmMethodParameterKind.VALUE) { 506 break; 507 } 508 invocationParamBuilder.addNextParameter(param.getAsmType(), false, null); 509 } 510 511 List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured(); 512 putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()])); 513 } 514 515 public void leaveTemps() { 516 FrameMap frameMap = codegen.getFrameMap(); 517 List<ParameterInfo> infos = invocationParamBuilder.listAllParams(); 518 for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { 519 ParameterInfo param = iterator.previous(); 520 if (!param.isSkippedOrRemapped()) { 521 frameMap.leaveTemp(param.type); 522 } 523 } 524 } 525 526 /*lambda or callable reference*/ 527 public static boolean isInliningParameter(JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) { 528 //TODO deparenthisise typed 529 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression); 530 return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && 531 isInlinableParameterExpression(deparenthesized); 532 } 533 534 protected static boolean isInlinableParameterExpression(JetExpression deparenthesized) { 535 return deparenthesized instanceof JetFunctionLiteralExpression || 536 deparenthesized instanceof JetNamedFunction || 537 deparenthesized instanceof JetCallableReferenceExpression; 538 } 539 540 public void rememberClosure(JetExpression expression, Type type) { 541 JetExpression lambda = JetPsiUtil.deparenthesize(expression); 542 assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); 543 544 LambdaInfo info = new LambdaInfo(lambda, typeMapper); 545 546 ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null); 547 closureInfo.setLambda(info); 548 expressionMap.put(closureInfo.getIndex(), info); 549 } 550 551 @NotNull 552 protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) { 553 Set<String> result = new HashSet<String>(); 554 if (lambdaOrFun != null) { 555 PsiElement parent = lambdaOrFun.getParent(); 556 if (parent instanceof JetLabeledExpression) { 557 String labelName = ((JetLabeledExpression) parent).getLabelName(); 558 assert labelName != null : "Labeled expression should have not nul label " + parent.getText(); 559 result.add(labelName); 560 } 561 } 562 if (!isFunctionLiteral(descriptor)) { 563 if (!descriptor.getName().isSpecial()) { 564 result.add(descriptor.getName().asString()); 565 } 566 result.add(InlineCodegenUtil.FIRST_FUN_LABEL); 567 } 568 return result; 569 } 570 571 private void putClosureParametersOnStack() { 572 for (LambdaInfo next : expressionMap.values()) { 573 activeLambda = next; 574 codegen.pushClosureOnStack(next.getClassDescriptor(), true, this); 575 } 576 activeLambda = null; 577 } 578 579 public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) { 580 if (descriptor instanceof PackageFragmentDescriptor) { 581 return new PackageContext((PackageFragmentDescriptor) descriptor, null, null); 582 } 583 584 CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state); 585 586 if (descriptor instanceof ClassDescriptor) { 587 OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION; 588 return parent.intoClass((ClassDescriptor) descriptor, kind, state); 589 } 590 else if (descriptor instanceof ScriptDescriptor) { 591 ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor); 592 assert classDescriptorForScript != null : "Can't find class for script: " + descriptor; 593 List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter(); 594 return parent.intoScript((ScriptDescriptor) descriptor, 595 earlierScripts == null ? Collections.emptyList() : earlierScripts, 596 classDescriptorForScript); 597 } 598 else if (descriptor instanceof FunctionDescriptor) { 599 return parent.intoFunction((FunctionDescriptor) descriptor); 600 } 601 602 throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor)); 603 } 604 605 private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) { 606 return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0; 607 } 608 609 private static String descriptorName(DeclarationDescriptor descriptor) { 610 return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor); 611 } 612 613 @Override 614 public void genValueAndPut( 615 @NotNull ValueParameterDescriptor valueParameterDescriptor, 616 @NotNull JetExpression argumentExpression, 617 @NotNull Type parameterType 618 ) { 619 if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { 620 rememberClosure(argumentExpression, parameterType); 621 } 622 else { 623 StackValue value = codegen.gen(argumentExpression); 624 putValueIfNeeded(valueParameterDescriptor, parameterType, value); 625 } 626 } 627 628 @Override 629 public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { 630 if (shouldPutValue(parameterType, value, valueParameterDescriptor)) { 631 value.put(parameterType, codegen.v); 632 } 633 afterParameterPut(parameterType, value, valueParameterDescriptor); 634 } 635 636 @Override 637 public void putCapturedValueOnStack( 638 @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex 639 ) { 640 if (shouldPutValue(stackValue.type, stackValue, null)) { 641 stackValue.put(stackValue.type, codegen.v); 642 } 643 putCapturedInLocal(stackValue.type, stackValue, null, paramIndex); 644 } 645 646 647 public void generateAndInsertFinallyBlocks( 648 MethodNode intoNode, 649 List<MethodInliner.PointForExternalFinallyBlocks> insertPoints, 650 int offsetForFinallyLocalVar 651 ) { 652 if (!codegen.hasFinallyBlocks()) return; 653 654 Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints = 655 new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>(); 656 for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) { 657 extensionPoints.put(insertPoint.beforeIns, insertPoint); 658 } 659 660 DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); 661 662 AbstractInsnNode curInstr = intoNode.instructions.getFirst(); 663 while (curInstr != null) { 664 processor.processInstruction(curInstr, true); 665 666 MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); 667 if (extension != null) { 668 Label start = new Label(); 669 Label end = new Label(); 670 671 MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); 672 finallyNode.visitLabel(start); 673 674 ExpressionCodegen finallyCodegen = 675 new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(), 676 codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); 677 finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements()); 678 679 FrameMap frameMap = finallyCodegen.getFrameMap(); 680 FrameMap.Mark mark = frameMap.mark(); 681 while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) { 682 frameMap.enterTemp(Type.INT_TYPE); 683 } 684 685 finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType); 686 finallyNode.visitLabel(end); 687 //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method 688 InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); 689 690 SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, (LabelNode) end.info); 691 processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false); 692 693 processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false); 694 695 mark.dropTo(); 696 } 697 698 curInstr = curInstr.getNext(); 699 } 700 701 processor.substituteTryBlockNodes(intoNode); 702 703 //processor.substituteLocalVarTable(intoNode); 704 } 705 706 private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { 707 return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); 708 } 709 710 }