21 * $Id: MethodGenerator.java,v 1.2.4.1 2005/09/05 11:16:47 pvedula Exp $ |
22 * $Id: MethodGenerator.java,v 1.2.4.1 2005/09/05 11:16:47 pvedula Exp $ |
22 */ |
23 */ |
23 |
24 |
24 package com.sun.org.apache.xalan.internal.xsltc.compiler.util; |
25 package com.sun.org.apache.xalan.internal.xsltc.compiler.util; |
25 |
26 |
26 import java.util.ArrayList; |
|
27 import java.util.Collections; |
|
28 import java.util.HashMap; |
|
29 import java.util.Iterator; |
|
30 import java.util.Map; |
|
31 import java.util.Stack; |
|
32 |
|
33 |
|
34 import com.sun.org.apache.bcel.internal.Const; |
27 import com.sun.org.apache.bcel.internal.Const; |
35 import com.sun.org.apache.bcel.internal.classfile.Field; |
28 import com.sun.org.apache.bcel.internal.classfile.Field; |
36 import com.sun.org.apache.bcel.internal.classfile.Method; |
29 import com.sun.org.apache.bcel.internal.classfile.Method; |
37 import com.sun.org.apache.bcel.internal.generic.ALOAD; |
30 import com.sun.org.apache.bcel.internal.generic.ALOAD; |
38 import com.sun.org.apache.bcel.internal.generic.ASTORE; |
31 import com.sun.org.apache.bcel.internal.generic.ASTORE; |
44 import com.sun.org.apache.bcel.internal.generic.FLOAD; |
37 import com.sun.org.apache.bcel.internal.generic.FLOAD; |
45 import com.sun.org.apache.bcel.internal.generic.FSTORE; |
38 import com.sun.org.apache.bcel.internal.generic.FSTORE; |
46 import com.sun.org.apache.bcel.internal.generic.GETFIELD; |
39 import com.sun.org.apache.bcel.internal.generic.GETFIELD; |
47 import com.sun.org.apache.bcel.internal.generic.GOTO; |
40 import com.sun.org.apache.bcel.internal.generic.GOTO; |
48 import com.sun.org.apache.bcel.internal.generic.ICONST; |
41 import com.sun.org.apache.bcel.internal.generic.ICONST; |
49 import com.sun.org.apache.bcel.internal.generic.IfInstruction; |
|
50 import com.sun.org.apache.bcel.internal.generic.ILOAD; |
42 import com.sun.org.apache.bcel.internal.generic.ILOAD; |
51 import com.sun.org.apache.bcel.internal.generic.IndexedInstruction; |
|
52 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; |
43 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; |
53 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; |
44 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; |
54 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; |
45 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; |
55 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; |
46 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; |
56 import com.sun.org.apache.bcel.internal.generic.ISTORE; |
47 import com.sun.org.apache.bcel.internal.generic.ISTORE; |
|
48 import com.sun.org.apache.bcel.internal.generic.IfInstruction; |
|
49 import com.sun.org.apache.bcel.internal.generic.IndexedInstruction; |
57 import com.sun.org.apache.bcel.internal.generic.Instruction; |
50 import com.sun.org.apache.bcel.internal.generic.Instruction; |
58 import com.sun.org.apache.bcel.internal.generic.InstructionConst; |
51 import com.sun.org.apache.bcel.internal.generic.InstructionConst; |
59 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; |
52 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; |
60 import com.sun.org.apache.bcel.internal.generic.InstructionList; |
53 import com.sun.org.apache.bcel.internal.generic.InstructionList; |
61 import com.sun.org.apache.bcel.internal.generic.InstructionTargeter; |
54 import com.sun.org.apache.bcel.internal.generic.InstructionTargeter; |
|
55 import com.sun.org.apache.bcel.internal.generic.LLOAD; |
|
56 import com.sun.org.apache.bcel.internal.generic.LSTORE; |
62 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; |
57 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; |
63 import com.sun.org.apache.bcel.internal.generic.LocalVariableInstruction; |
58 import com.sun.org.apache.bcel.internal.generic.LocalVariableInstruction; |
64 import com.sun.org.apache.bcel.internal.generic.LLOAD; |
|
65 import com.sun.org.apache.bcel.internal.generic.LSTORE; |
|
66 import com.sun.org.apache.bcel.internal.generic.MethodGen; |
59 import com.sun.org.apache.bcel.internal.generic.MethodGen; |
67 import com.sun.org.apache.bcel.internal.generic.NEW; |
60 import com.sun.org.apache.bcel.internal.generic.NEW; |
68 import com.sun.org.apache.bcel.internal.generic.PUTFIELD; |
61 import com.sun.org.apache.bcel.internal.generic.PUTFIELD; |
69 import com.sun.org.apache.bcel.internal.generic.RET; |
62 import com.sun.org.apache.bcel.internal.generic.RET; |
70 import com.sun.org.apache.bcel.internal.generic.Select; |
63 import com.sun.org.apache.bcel.internal.generic.Select; |
71 import com.sun.org.apache.bcel.internal.generic.TargetLostException; |
64 import com.sun.org.apache.bcel.internal.generic.TargetLostException; |
72 import com.sun.org.apache.bcel.internal.generic.Type; |
65 import com.sun.org.apache.bcel.internal.generic.Type; |
73 |
|
74 import com.sun.org.apache.xalan.internal.xsltc.compiler.Pattern; |
66 import com.sun.org.apache.xalan.internal.xsltc.compiler.Pattern; |
75 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC; |
67 import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC; |
|
68 import java.util.ArrayList; |
|
69 import java.util.Collections; |
|
70 import java.util.HashMap; |
|
71 import java.util.Iterator; |
|
72 import java.util.List; |
|
73 import java.util.Map; |
|
74 import java.util.Stack; |
76 |
75 |
77 /** |
76 /** |
78 * @author Jacek Ambroziak |
77 * @author Jacek Ambroziak |
79 * @author Santiago Pericas-Geertsen |
78 * @author Santiago Pericas-Geertsen |
80 */ |
79 */ |
264 * {@link #outline(InstructionHandle,InstructionHandle,String,ClassGenerator)}, |
263 * {@link #outline(InstructionHandle,InstructionHandle,String,ClassGenerator)}, |
265 * this class keeps track of all local variables defined by the method.</p> |
264 * this class keeps track of all local variables defined by the method.</p> |
266 */ |
265 */ |
267 protected class LocalVariableRegistry { |
266 protected class LocalVariableRegistry { |
268 /** |
267 /** |
269 * <p>A <code>java.lang.ArrayList</code> of all |
268 * <p>A <code>java.lang.List</code> of all |
270 * {@link LocalVariableGen}s created for this method, indexed by the |
269 * {@link LocalVariableGen}s created for this method, indexed by the |
271 * slot number of the local variable. The JVM stack frame of local |
270 * slot number of the local variable. The JVM stack frame of local |
272 * variables is divided into "slots". A single slot can be used to |
271 * variables is divided into "slots". A single slot can be used to |
273 * store more than one variable in a method, without regard to type, so |
272 * store more than one variable in a method, without regard to type, so |
274 * long as the byte code keeps the ranges of the two disjoint.</p> |
273 * long as the byte code keeps the ranges of the two disjoint.</p> |
277 * <code>LocalVariableGen</code>; if more than one occurs, the |
276 * <code>LocalVariableGen</code>; if more than one occurs, the |
278 * corresponding entry contains all such <code>LocalVariableGen</code>s |
277 * corresponding entry contains all such <code>LocalVariableGen</code>s |
279 * registered for the same slot; and if none occurs, the entry will be |
278 * registered for the same slot; and if none occurs, the entry will be |
280 * <code>null</code>. |
279 * <code>null</code>. |
281 */ |
280 */ |
282 protected ArrayList _variables = new ArrayList(); |
281 protected List<Object> _variables = new ArrayList<>(); |
283 |
282 |
284 /** |
283 /** |
285 * Maps a name to a {@link LocalVariableGen} |
284 * Maps a name to a {@link LocalVariableGen} |
286 */ |
285 */ |
287 protected HashMap _nameToLVGMap = new HashMap(); |
286 protected Map<String, Object> _nameToLVGMap = new HashMap<>(); |
288 |
287 |
289 /** |
288 /** |
290 * Registers a {@link org.apache.bcel.generic.LocalVariableGen} |
289 * Registers a {@link org.apache.bcel.generic.LocalVariableGen} |
291 * for this method. |
290 * for this method. |
292 * <p><b>Preconditions:</b> |
291 * <p><b>Preconditions:</b> |
318 // _variables just contains null padding, store the |
318 // _variables just contains null padding, store the |
319 // LocalVariableGen directly. |
319 // LocalVariableGen directly. |
320 Object localsInSlot = _variables.get(slot); |
320 Object localsInSlot = _variables.get(slot); |
321 if (localsInSlot != null) { |
321 if (localsInSlot != null) { |
322 if (localsInSlot instanceof LocalVariableGen) { |
322 if (localsInSlot instanceof LocalVariableGen) { |
323 ArrayList listOfLocalsInSlot = new ArrayList(); |
323 List<LocalVariableGen> listOfLocalsInSlot = new ArrayList<>(); |
324 listOfLocalsInSlot.add(localsInSlot); |
324 listOfLocalsInSlot.add((LocalVariableGen)localsInSlot); |
325 listOfLocalsInSlot.add(lvg); |
325 listOfLocalsInSlot.add(lvg); |
326 _variables.set(slot, listOfLocalsInSlot); |
326 _variables.set(slot, listOfLocalsInSlot); |
327 } else { |
327 } else { |
328 ((ArrayList) localsInSlot).add(lvg); |
328 ((List<LocalVariableGen>) localsInSlot).add(lvg); |
329 } |
329 } |
330 } else { |
330 } else { |
331 _variables.set(slot, lvg); |
331 _variables.set(slot, lvg); |
332 } |
332 } |
333 } |
333 } |
367 LocalVariableGen lvg = (LocalVariableGen)localsInSlot; |
367 LocalVariableGen lvg = (LocalVariableGen)localsInSlot; |
368 if (offsetInLocalVariableGenRange(lvg, offset)) { |
368 if (offsetInLocalVariableGenRange(lvg, offset)) { |
369 return lvg; |
369 return lvg; |
370 } |
370 } |
371 } else { |
371 } else { |
372 ArrayList listOfLocalsInSlot = (ArrayList) localsInSlot; |
372 @SuppressWarnings("unchecked") |
373 int size = listOfLocalsInSlot.size(); |
373 List<LocalVariableGen> listOfLocalsInSlot = |
374 |
374 (List<LocalVariableGen>) localsInSlot; |
375 for (int i = 0; i < size; i++) { |
375 |
376 LocalVariableGen lvg = |
376 for (LocalVariableGen lvg : listOfLocalsInSlot) { |
377 (LocalVariableGen)listOfLocalsInSlot.get(i); |
|
378 if (offsetInLocalVariableGenRange(lvg, offset)) { |
377 if (offsetInLocalVariableGenRange(lvg, offset)) { |
379 return lvg; |
378 return lvg; |
380 } |
379 } |
381 } |
380 } |
382 } |
381 } |
401 * set, which causes problems for outlining..</p> |
400 * set, which causes problems for outlining..</p> |
402 * <p>See also {@link #lookUpByName(String)} and |
401 * <p>See also {@link #lookUpByName(String)} and |
403 * {@link #removeByNameTracking(LocalVariableGen)}</P |
402 * {@link #removeByNameTracking(LocalVariableGen)}</P |
404 * @param lvg a <code>LocalVariableGen</code> |
403 * @param lvg a <code>LocalVariableGen</code> |
405 */ |
404 */ |
|
405 @SuppressWarnings("unchecked") |
406 protected void registerByName(LocalVariableGen lvg) { |
406 protected void registerByName(LocalVariableGen lvg) { |
407 Object duplicateNameEntry = _nameToLVGMap.get(lvg.getName()); |
407 Object duplicateNameEntry = _nameToLVGMap.get(lvg.getName()); |
408 |
408 |
409 if (duplicateNameEntry == null) { |
409 if (duplicateNameEntry == null) { |
410 _nameToLVGMap.put(lvg.getName(), lvg); |
410 _nameToLVGMap.put(lvg.getName(), lvg); |
411 } else { |
411 } else { |
412 ArrayList sameNameList; |
412 List<LocalVariableGen> sameNameList; |
413 |
413 |
414 if (duplicateNameEntry instanceof ArrayList) { |
414 if (duplicateNameEntry instanceof ArrayList) { |
415 sameNameList = (ArrayList) duplicateNameEntry; |
415 sameNameList = (List<LocalVariableGen>)duplicateNameEntry; |
416 sameNameList.add(lvg); |
416 sameNameList.add(lvg); |
417 } else { |
417 } else { |
418 sameNameList = new ArrayList(); |
418 sameNameList = new ArrayList<>(); |
419 sameNameList.add(duplicateNameEntry); |
419 sameNameList.add((LocalVariableGen)duplicateNameEntry); |
420 sameNameList.add(lvg); |
420 sameNameList.add(lvg); |
421 } |
421 } |
422 |
422 |
423 _nameToLVGMap.put(lvg.getName(), sameNameList); |
423 _nameToLVGMap.put(lvg.getName(), sameNameList); |
424 } |
424 } |
429 * {@link LocalVariableGen} to itself. |
429 * {@link LocalVariableGen} to itself. |
430 * See also {@link #registerByName(LocalVariableGen)} and |
430 * See also {@link #registerByName(LocalVariableGen)} and |
431 * {@link #lookUpByName(String)} |
431 * {@link #lookUpByName(String)} |
432 * @param lvg a <code>LocalVariableGen</code> |
432 * @param lvg a <code>LocalVariableGen</code> |
433 */ |
433 */ |
|
434 @SuppressWarnings("unchecked") |
434 protected void removeByNameTracking(LocalVariableGen lvg) { |
435 protected void removeByNameTracking(LocalVariableGen lvg) { |
435 Object duplicateNameEntry = _nameToLVGMap.get(lvg.getName()); |
436 Object duplicateNameEntry = _nameToLVGMap.get(lvg.getName()); |
436 |
437 |
437 if (duplicateNameEntry instanceof ArrayList) { |
438 if (duplicateNameEntry instanceof ArrayList) { |
438 ArrayList sameNameList = (ArrayList) duplicateNameEntry; |
439 List<LocalVariableGen> sameNameList = |
|
440 (List<LocalVariableGen>)duplicateNameEntry; |
439 for (int i = 0; i < sameNameList.size(); i++) { |
441 for (int i = 0; i < sameNameList.size(); i++) { |
440 if (sameNameList.get(i) == lvg) { |
442 if (sameNameList.get(i) == lvg) { |
441 sameNameList.remove(i); |
443 sameNameList.remove(i); |
442 break; |
444 break; |
443 } |
445 } |
453 * <p>See also {@link #registerByName(LocalVariableGen)} and |
455 * <p>See also {@link #registerByName(LocalVariableGen)} and |
454 * {@link #removeByNameTracking(LocalVariableGen)}</p> |
456 * {@link #removeByNameTracking(LocalVariableGen)}</p> |
455 * @param name |
457 * @param name |
456 * @return |
458 * @return |
457 */ |
459 */ |
|
460 @SuppressWarnings("unchecked") |
458 protected LocalVariableGen lookUpByName(String name) { |
461 protected LocalVariableGen lookUpByName(String name) { |
459 LocalVariableGen lvg = null; |
462 LocalVariableGen lvg = null; |
460 Object duplicateNameEntry = _nameToLVGMap.get(name); |
463 Object duplicateNameEntry = _nameToLVGMap.get(name); |
461 |
464 |
462 if (duplicateNameEntry instanceof ArrayList) { |
465 if (duplicateNameEntry instanceof ArrayList) { |
463 ArrayList sameNameList = (ArrayList) duplicateNameEntry; |
466 List<LocalVariableGen> sameNameList = |
|
467 (List<LocalVariableGen>)duplicateNameEntry; |
464 |
468 |
465 for (int i = 0; i < sameNameList.size(); i++) { |
469 for (int i = 0; i < sameNameList.size(); i++) { |
466 lvg = (LocalVariableGen)sameNameList.get(i); |
470 lvg = sameNameList.get(i); |
467 if (lvg.getName() == name) { |
471 if (lvg.getName() == null ? name == null : lvg.getName().equals(name)) { |
468 break; |
472 break; |
469 } |
473 } |
470 } |
474 } |
471 } else { |
475 } else { |
472 lvg = (LocalVariableGen) duplicateNameEntry; |
476 lvg = (LocalVariableGen) duplicateNameEntry; |
487 * declared should be returned (<code>true</code>) or only those not |
491 * declared should be returned (<code>true</code>) or only those not |
488 * removed (<code>false</code>) |
492 * removed (<code>false</code>) |
489 * @return an array of <code>LocalVariableGen</code> containing all the |
493 * @return an array of <code>LocalVariableGen</code> containing all the |
490 * local variables |
494 * local variables |
491 */ |
495 */ |
|
496 @SuppressWarnings("unchecked") |
492 protected LocalVariableGen[] getLocals(boolean includeRemoved) { |
497 protected LocalVariableGen[] getLocals(boolean includeRemoved) { |
493 LocalVariableGen[] locals = null; |
498 LocalVariableGen[] locals = null; |
494 ArrayList allVarsEverDeclared = new ArrayList(); |
499 List<LocalVariableGen> allVarsEverDeclared = new ArrayList<>(); |
495 |
500 |
496 if (includeRemoved) { |
501 if (includeRemoved) { |
497 int slotCount = allVarsEverDeclared.size(); |
502 int slotCount = allVarsEverDeclared.size(); |
498 |
503 |
499 for (int i = 0; i < slotCount; i++) { |
504 for (int i = 0; i < slotCount; i++) { |
500 Object slotEntries = _variables.get(i); |
505 Object slotEntries = _variables.get(i); |
501 if (slotEntries != null) { |
506 if (slotEntries != null) { |
502 if (slotEntries instanceof ArrayList) { |
507 if (slotEntries instanceof ArrayList) { |
503 ArrayList slotList = (ArrayList) slotEntries; |
508 List<LocalVariableGen> slotList = |
|
509 (List<LocalVariableGen>)slotEntries; |
504 |
510 |
505 for (int j = 0; j < slotList.size(); j++) { |
511 for (int j = 0; j < slotList.size(); j++) { |
506 allVarsEverDeclared.add(slotList.get(i)); |
512 allVarsEverDeclared.add(slotList.get(i)); |
507 } |
513 } |
508 } else { |
514 } else { |
509 allVarsEverDeclared.add(slotEntries); |
515 allVarsEverDeclared.add((LocalVariableGen)slotEntries); |
510 } |
516 } |
511 } |
517 } |
512 } |
518 } |
513 } else { |
519 } else { |
514 Iterator nameVarsPairsIter = _nameToLVGMap.entrySet().iterator(); |
520 for (Map.Entry<String, Object> nameVarsPair : _nameToLVGMap.entrySet()) { |
515 |
|
516 while (nameVarsPairsIter.hasNext()) { |
|
517 Map.Entry nameVarsPair = |
|
518 (Map.Entry) nameVarsPairsIter.next(); |
|
519 Object vars = nameVarsPair.getValue(); |
521 Object vars = nameVarsPair.getValue(); |
520 if (vars != null) { |
522 if (vars != null) { |
521 if (vars instanceof ArrayList) { |
523 if (vars instanceof ArrayList) { |
522 ArrayList varsList = (ArrayList) vars; |
524 List<LocalVariableGen> varsList = |
|
525 (List<LocalVariableGen>) vars; |
523 for (int i = 0; i < varsList.size(); i++) { |
526 for (int i = 0; i < varsList.size(); i++) { |
524 allVarsEverDeclared.add(varsList.get(i)); |
527 allVarsEverDeclared.add(varsList.get(i)); |
525 } |
528 } |
526 } else { |
529 } else { |
527 allVarsEverDeclared.add(vars); |
530 allVarsEverDeclared.add((LocalVariableGen)vars); |
528 } |
531 } |
529 } |
532 } |
530 } |
533 } |
531 } |
534 } |
532 |
535 |
819 * Find the outlineable chunks in this method that would be the best choices |
822 * Find the outlineable chunks in this method that would be the best choices |
820 * to outline, based on size and position in the method. |
823 * to outline, based on size and position in the method. |
821 * @param classGen The {@link ClassGen} with which the generated methods |
824 * @param classGen The {@link ClassGen} with which the generated methods |
822 * will be associated |
825 * will be associated |
823 * @param totalMethodSize the size of the bytecode in the original method |
826 * @param totalMethodSize the size of the bytecode in the original method |
824 * @return a <code>java.util.ArrayList</code> containing the |
827 * @return a <code>java.util.List</code> containing the |
825 * {@link MethodGenerator.Chunk}s that may be outlined from this method |
828 * {@link MethodGenerator.Chunk}s that may be outlined from this method |
826 */ |
829 */ |
827 private ArrayList getCandidateChunks(ClassGenerator classGen, |
830 private List<Chunk> getCandidateChunks(ClassGenerator classGen, |
828 int totalMethodSize) { |
831 int totalMethodSize) { |
829 Iterator instructions = getInstructionList().iterator(); |
832 Iterator<InstructionHandle> instructions = getInstructionList().iterator(); |
830 ArrayList candidateChunks = new ArrayList(); |
833 List<Chunk> candidateChunks = new ArrayList<>(); |
831 ArrayList currLevelChunks = new ArrayList(); |
834 List<InstructionHandle> currLevelChunks = new ArrayList<>(); |
832 Stack subChunkStack = new Stack(); |
835 Stack<List<InstructionHandle>> subChunkStack = new Stack<>(); |
833 boolean openChunkAtCurrLevel = false; |
836 boolean openChunkAtCurrLevel = false; |
834 boolean firstInstruction = true; |
837 boolean firstInstruction = true; |
835 |
838 |
836 InstructionHandle currentHandle; |
839 InstructionHandle currentHandle; |
837 |
840 |
882 // OutlineableChunkStart, this represents the first chunk |
885 // OutlineableChunkStart, this represents the first chunk |
883 // nested within that previous chunk - push the list of chunks |
886 // nested within that previous chunk - push the list of chunks |
884 // from the outer level onto the stack |
887 // from the outer level onto the stack |
885 if (openChunkAtCurrLevel) { |
888 if (openChunkAtCurrLevel) { |
886 subChunkStack.push(currLevelChunks); |
889 subChunkStack.push(currLevelChunks); |
887 currLevelChunks = new ArrayList(); |
890 currLevelChunks = new ArrayList<>(); |
888 } |
891 } |
889 |
892 |
890 openChunkAtCurrLevel = true; |
893 openChunkAtCurrLevel = true; |
891 currLevelChunks.add(currentHandle); |
894 currLevelChunks.add(currentHandle); |
892 // Close off an open chunk |
895 // Close off an open chunk |
893 } else if (currentHandle == null |
896 } else if (currentHandle == null |
894 || inst instanceof OutlineableChunkEnd) { |
897 || inst instanceof OutlineableChunkEnd) { |
895 ArrayList nestedSubChunks = null; |
898 List<InstructionHandle> nestedSubChunks = null; |
896 |
899 |
897 // If the last MarkerInstruction encountered was an |
900 // If the last MarkerInstruction encountered was an |
898 // OutlineableChunkEnd, it means that the current instruction |
901 // OutlineableChunkEnd, it means that the current instruction |
899 // marks the end of a chunk that contained child chunks. |
902 // marks the end of a chunk that contained child chunks. |
900 // Those children might need to be examined below in case they |
903 // Those children might need to be examined below in case they |
901 // are better candidates for outlining than the current chunk. |
904 // are better candidates for outlining than the current chunk. |
902 if (!openChunkAtCurrLevel) { |
905 if (!openChunkAtCurrLevel) { |
903 nestedSubChunks = currLevelChunks; |
906 nestedSubChunks = currLevelChunks; |
904 currLevelChunks = (ArrayList)subChunkStack.pop(); |
907 currLevelChunks = (List<InstructionHandle>)subChunkStack.pop(); |
905 } |
908 } |
906 |
909 |
907 // Get the handle for the start of this chunk (the last entry |
910 // Get the handle for the start of this chunk (the last entry |
908 // in currLevelChunks) |
911 // in currLevelChunks) |
909 InstructionHandle chunkStart = |
912 InstructionHandle chunkStart = |
946 |
949 |
947 childChunks[i] = new Chunk(start, end); |
950 childChunks[i] = new Chunk(start, end); |
948 } |
951 } |
949 |
952 |
950 // Merge adjacent siblings |
953 // Merge adjacent siblings |
951 ArrayList mergedChildChunks = |
954 List<Chunk> mergedChildChunks = |
952 mergeAdjacentChunks(childChunks); |
955 mergeAdjacentChunks(childChunks); |
953 |
956 |
954 // Add chunks that mean minimum size requirements |
957 // Add chunks that mean minimum size requirements |
955 // to the list of candidate chunks for outlining |
958 // to the list of candidate chunks for outlining |
956 for (int i = 0; i < mergedChildChunks.size(); i++) { |
959 for (Chunk mergedChunk : mergedChildChunks) { |
957 Chunk mergedChunk = |
|
958 (Chunk)mergedChildChunks.get(i); |
|
959 int mergedSize = mergedChunk.getChunkSize(); |
960 int mergedSize = mergedChunk.getChunkSize(); |
960 |
961 |
961 if (mergedSize >= MINIMUM_OUTLINEABLE_CHUNK_SIZE |
962 if (mergedSize >= MINIMUM_OUTLINEABLE_CHUNK_SIZE |
962 && mergedSize <= TARGET_METHOD_SIZE) { |
963 && mergedSize <= TARGET_METHOD_SIZE) { |
963 candidateChunks.add(mergedChunk); |
964 candidateChunks.add(mergedChunk); |
985 * Merge adjacent sibling chunks to produce larger candidate chunks for |
986 * Merge adjacent sibling chunks to produce larger candidate chunks for |
986 * outlining |
987 * outlining |
987 * @param chunks array of sibling {@link MethodGenerator.Chunk}s that are |
988 * @param chunks array of sibling {@link MethodGenerator.Chunk}s that are |
988 * under consideration for outlining. Chunks must be in |
989 * under consideration for outlining. Chunks must be in |
989 * the order encountered in the {@link InstructionList} |
990 * the order encountered in the {@link InstructionList} |
990 * @return a <code>java.util.ArrayList</code> of |
991 * @return a <code>java.util.List</code> of |
991 * <code>MethodGenerator.Chunk</code>s maximally merged |
992 * <code>MethodGenerator.Chunk</code>s maximally merged |
992 */ |
993 */ |
993 private ArrayList mergeAdjacentChunks(Chunk[] chunks) { |
994 private List<Chunk> mergeAdjacentChunks(Chunk[] chunks) { |
994 int[] adjacencyRunStart = new int[chunks.length]; |
995 int[] adjacencyRunStart = new int[chunks.length]; |
995 int[] adjacencyRunLength = new int[chunks.length]; |
996 int[] adjacencyRunLength = new int[chunks.length]; |
996 boolean[] chunkWasMerged = new boolean[chunks.length]; |
997 boolean[] chunkWasMerged = new boolean[chunks.length]; |
997 |
998 |
998 int maximumRunOfChunks = 0; |
999 int maximumRunOfChunks = 0; |
999 int startOfCurrentRun; |
1000 int startOfCurrentRun; |
1000 int numAdjacentRuns = 0; |
1001 int numAdjacentRuns = 0; |
1001 |
1002 |
1002 ArrayList mergedChunks = new ArrayList(); |
1003 List<Chunk> mergedChunks = new ArrayList<>(); |
1003 |
1004 |
1004 startOfCurrentRun = 0; |
1005 startOfCurrentRun = 0; |
1005 |
1006 |
1006 // Loop through chunks, and record in adjacencyRunStart where each |
1007 // Loop through chunks, and record in adjacencyRunStart where each |
1007 // run of adjacent chunks begins and how many are in that run. For |
1008 // run of adjacent chunks begins and how many are in that run. For |
1131 * @return an array of the outlined <code>Method</code>s and the original |
1132 * @return an array of the outlined <code>Method</code>s and the original |
1132 * method itself |
1133 * method itself |
1133 */ |
1134 */ |
1134 public Method[] outlineChunks(ClassGenerator classGen, |
1135 public Method[] outlineChunks(ClassGenerator classGen, |
1135 int originalMethodSize) { |
1136 int originalMethodSize) { |
1136 ArrayList methodsOutlined = new ArrayList(); |
1137 List<Method> methodsOutlined = new ArrayList<>(); |
1137 int currentMethodSize = originalMethodSize; |
1138 int currentMethodSize = originalMethodSize; |
1138 |
1139 |
1139 int outlinedCount = 0; |
1140 int outlinedCount = 0; |
1140 boolean moreMethodsOutlined; |
1141 boolean moreMethodsOutlined; |
1141 String originalMethodName = getName(); |
1142 String originalMethodName = getName(); |
1350 |
1351 |
1351 // Keeps track of the mapping from instruction handles in the old |
1352 // Keeps track of the mapping from instruction handles in the old |
1352 // method to instruction handles in the outlined method. Only need |
1353 // method to instruction handles in the outlined method. Only need |
1353 // to track instructions that are targeted by something else in the |
1354 // to track instructions that are targeted by something else in the |
1354 // generated BCEL |
1355 // generated BCEL |
1355 HashMap targetMap = new HashMap(); |
1356 HashMap<InstructionHandle, InstructionHandle> targetMap = new HashMap<>(); |
1356 |
1357 |
1357 // Keeps track of the mapping from local variables in the old method |
1358 // Keeps track of the mapping from local variables in the old method |
1358 // to local variables in the outlined method. |
1359 // to local variables in the outlined method. |
1359 HashMap localVarMap = new HashMap(); |
1360 HashMap<LocalVariableGen, LocalVariableGen> localVarMap = new HashMap<>(); |
1360 |
1361 |
1361 HashMap revisedLocalVarStart = new HashMap(); |
1362 HashMap<LocalVariableGen, InstructionHandle> revisedLocalVarStart = new HashMap<>(); |
1362 HashMap revisedLocalVarEnd = new HashMap(); |
1363 HashMap<LocalVariableGen, InstructionHandle> revisedLocalVarEnd = new HashMap<>(); |
1363 |
1364 |
1364 // Pass 1: Make copies of all instructions, append them to the new list |
1365 // Pass 1: Make copies of all instructions, append them to the new list |
1365 // and associate old instruction references with the new ones, i.e., |
1366 // and associate old instruction references with the new ones, i.e., |
1366 // a 1:1 mapping. The special marker instructions are not copied. |
1367 // a 1:1 mapping. The special marker instructions are not copied. |
1367 // Also, identify local variables whose values need to be copied into or |
1368 // Also, identify local variables whose values need to be copied into or |
1413 int oldLocalVarIndex = lvi.getIndex(); |
1414 int oldLocalVarIndex = lvi.getIndex(); |
1414 LocalVariableGen oldLVG = |
1415 LocalVariableGen oldLVG = |
1415 getLocalVariableRegistry() |
1416 getLocalVariableRegistry() |
1416 .lookupRegisteredLocalVariable(oldLocalVarIndex, |
1417 .lookupRegisteredLocalVariable(oldLocalVarIndex, |
1417 ih.getPosition()); |
1418 ih.getPosition()); |
1418 LocalVariableGen newLVG = |
1419 LocalVariableGen newLVG = localVarMap.get(oldLVG); |
1419 (LocalVariableGen)localVarMap.get(oldLVG); |
|
1420 |
1420 |
1421 // Has the code already mapped this local variable to a |
1421 // Has the code already mapped this local variable to a |
1422 // local in the new method? |
1422 // local in the new method? |
1423 if (localVarMap.get(oldLVG) == null) { |
1423 if (localVarMap.get(oldLVG) == null) { |
1424 // Determine whether the local variable needs to be |
1424 // Determine whether the local variable needs to be |
1572 BranchInstruction bc = (BranchInstruction)c; |
1572 BranchInstruction bc = (BranchInstruction)c; |
1573 BranchInstruction bi = (BranchInstruction)i; |
1573 BranchInstruction bi = (BranchInstruction)i; |
1574 InstructionHandle itarget = bi.getTarget(); // old target |
1574 InstructionHandle itarget = bi.getTarget(); // old target |
1575 |
1575 |
1576 // New target must be in targetMap |
1576 // New target must be in targetMap |
1577 InstructionHandle newTarget = |
1577 InstructionHandle newTarget = targetMap.get(itarget); |
1578 (InstructionHandle)targetMap.get(itarget); |
|
1579 |
1578 |
1580 bc.setTarget(newTarget); |
1579 bc.setTarget(newTarget); |
1581 |
1580 |
1582 // Handle LOOKUPSWITCH or TABLESWITCH which may have many |
1581 // Handle LOOKUPSWITCH or TABLESWITCH which may have many |
1583 // target instructions |
1582 // target instructions |
1585 InstructionHandle[] itargets = ((Select)bi).getTargets(); |
1584 InstructionHandle[] itargets = ((Select)bi).getTargets(); |
1586 InstructionHandle[] ctargets = ((Select)bc).getTargets(); |
1585 InstructionHandle[] ctargets = ((Select)bc).getTargets(); |
1587 |
1586 |
1588 // Update all targets |
1587 // Update all targets |
1589 for (int j=0; j < itargets.length; j++) { |
1588 for (int j=0; j < itargets.length; j++) { |
1590 ctargets[j] = |
1589 ctargets[j] = targetMap.get(itargets[j]); |
1591 (InstructionHandle)targetMap.get(itargets[j]); |
|
1592 } |
1590 } |
1593 } |
1591 } |
1594 } else if (i instanceof LocalVariableInstruction |
1592 } else if (i instanceof LocalVariableInstruction |
1595 || i instanceof RET) { |
1593 || i instanceof RET) { |
1596 // For any instruction that touches a local variable, |
1594 // For any instruction that touches a local variable, |
1600 int oldLocalVarIndex = lvi.getIndex(); |
1598 int oldLocalVarIndex = lvi.getIndex(); |
1601 LocalVariableGen oldLVG = |
1599 LocalVariableGen oldLVG = |
1602 getLocalVariableRegistry() |
1600 getLocalVariableRegistry() |
1603 .lookupRegisteredLocalVariable(oldLocalVarIndex, |
1601 .lookupRegisteredLocalVariable(oldLocalVarIndex, |
1604 ih.getPosition()); |
1602 ih.getPosition()); |
1605 LocalVariableGen newLVG = |
1603 LocalVariableGen newLVG = localVarMap.get(oldLVG); |
1606 (LocalVariableGen)localVarMap.get(oldLVG); |
|
1607 int newLocalVarIndex; |
1604 int newLocalVarIndex; |
1608 |
1605 |
1609 if (newLVG == null) { |
1606 if (newLVG == null) { |
1610 // Create new variable based on old variable - use same |
1607 // Create new variable based on old variable - use same |
1611 // name and type, but we will let the variable be active |
1608 // name and type, but we will let the variable be active |
1665 } |
1661 } |
1666 |
1662 |
1667 // POP the reference to the CopyLocals object from the stack |
1663 // POP the reference to the CopyLocals object from the stack |
1668 oldMethCopyOutIL.append(InstructionConst.POP); |
1664 oldMethCopyOutIL.append(InstructionConst.POP); |
1669 |
1665 |
1670 // Now that the generation of the outlined code is complete, update |
1666 for (Map.Entry<LocalVariableGen, InstructionHandle> lvgRangeStartPair : |
1671 // the old local variables with new start and end ranges, as required. |
1667 revisedLocalVarStart.entrySet()) { |
1672 Iterator revisedLocalVarStartPairIter = revisedLocalVarStart.entrySet() |
1668 LocalVariableGen lvg = lvgRangeStartPair.getKey(); |
1673 .iterator(); |
1669 InstructionHandle startInst = lvgRangeStartPair.getValue(); |
1674 while (revisedLocalVarStartPairIter.hasNext()) { |
|
1675 Map.Entry lvgRangeStartPair = |
|
1676 (Map.Entry)revisedLocalVarStartPairIter.next(); |
|
1677 LocalVariableGen lvg = (LocalVariableGen)lvgRangeStartPair.getKey(); |
|
1678 InstructionHandle startInst = |
|
1679 (InstructionHandle)lvgRangeStartPair.getValue(); |
|
1680 |
1670 |
1681 lvg.setStart(startInst); |
1671 lvg.setStart(startInst); |
1682 |
1672 } |
1683 } |
1673 |
1684 |
1674 for (Map.Entry<LocalVariableGen, InstructionHandle> lvgRangeEndPair : |
1685 Iterator revisedLocalVarEndPairIter = revisedLocalVarEnd.entrySet() |
1675 revisedLocalVarEnd.entrySet()) { |
1686 .iterator(); |
1676 LocalVariableGen lvg = lvgRangeEndPair.getKey(); |
1687 while (revisedLocalVarEndPairIter.hasNext()) { |
1677 InstructionHandle endInst = lvgRangeEndPair.getValue(); |
1688 Map.Entry lvgRangeEndPair = |
|
1689 (Map.Entry)revisedLocalVarEndPairIter.next(); |
|
1690 LocalVariableGen lvg = (LocalVariableGen)lvgRangeEndPair.getKey(); |
|
1691 InstructionHandle endInst = |
|
1692 (InstructionHandle)lvgRangeEndPair.getValue(); |
|
1693 |
1678 |
1694 lvg.setEnd(endInst); |
1679 lvg.setEnd(endInst); |
1695 } |
1680 } |
1696 |
1681 |
1697 xsltc.dumpClass(copyAreaCG.getJavaClass()); |
1682 xsltc.dumpClass(copyAreaCG.getJavaClass()); |