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