OSDN Git Service

cflib は plugins プロジェクトから,Stigmata直下のプロジェクトに移行したため,このリポジトリからは削除した.
[stigmata/stigmata-plugins.git] / wsp / src / main / java / jp / sourceforge / stigmata / birthmarks / wsp / StackPatternBasedBirthmarkExtractor.java
1 package jp.sourceforge.stigmata.birthmarks.wsp;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import jp.sourceforge.stigmata.Birthmark;
9 import jp.sourceforge.stigmata.BirthmarkContext;
10 import jp.sourceforge.stigmata.BirthmarkElement;
11 import jp.sourceforge.stigmata.ExtractionUnit;
12 import jp.sourceforge.stigmata.birthmarks.ASMBirthmarkExtractor;
13 import jp.sourceforge.stigmata.birthmarks.BirthmarkExtractVisitor;
14 import jp.sourceforge.stigmata.cflib.BirthmarkElementBuilder;
15 import jp.sourceforge.stigmata.cflib.LabelOpcode;
16 import jp.sourceforge.stigmata.cflib.Opcode;
17 import jp.sourceforge.stigmata.cflib.OpcodeExtractVisitor;
18 import jp.sourceforge.stigmata.spi.BirthmarkService;
19
20 import org.objectweb.asm.ClassWriter;
21 import org.objectweb.asm.Label;
22
23 /**
24  *
25  * @author Haruaki Tamada
26  */
27 public class StackPatternBasedBirthmarkExtractor
28         extends ASMBirthmarkExtractor{
29     public StackPatternBasedBirthmarkExtractor(BirthmarkService service){
30         super(service);
31     }
32
33     @Override
34     public BirthmarkExtractVisitor createExtractVisitor(
35             ClassWriter writer, Birthmark birthmark,
36             BirthmarkContext context){
37
38         return new OpcodeExtractVisitor(
39             writer, birthmark, context, new WSPBirthmarkElementBuilder()
40         );
41     }
42
43     @Override
44     public ExtractionUnit[] getAcceptableUnits(){
45         return new ExtractionUnit[] {
46             ExtractionUnit.CLASS,
47         };
48     }
49
50     private static class WSPBirthmarkElementBuilder
51             implements BirthmarkElementBuilder{
52         @Override
53         public BirthmarkElement[] buildElements(List<Opcode> opcodes,
54                                                 BirthmarkContext context){
55             List<CurrentDepth> pattern = buildStackPattern(opcodes, context);
56             List<BirthmarkElement> elements =
57                 new ArrayList<BirthmarkElement>();
58
59             List<CurrentDepth> subPattern = new ArrayList<CurrentDepth>();
60             for(CurrentDepth depth: pattern){
61                 subPattern.add(depth);
62                 if(depth.getDepth() == 0){
63                     elements.add(
64                         new StackPatternBasedBirthmarkElement(
65                             subPattern.toArray(
66                                 new CurrentDepth[subPattern.size()]
67                             )
68                         )
69                     );
70                     subPattern.clear();
71                 }
72             }
73             elements.add(
74                 new StackPatternBasedBirthmarkElement(
75                     subPattern.toArray(new CurrentDepth[subPattern.size()])
76                 )
77             );
78
79             return elements.toArray(new BirthmarkElement[elements.size()]);
80         }
81
82         @SuppressWarnings("unchecked")
83         private List<CurrentDepth> buildStackPattern(List<Opcode> opcodes,
84                 BirthmarkContext context){
85             Map<Label, Integer> tableMap = new HashMap<Label, Integer>();
86             List<CurrentDepth> pattern = new ArrayList<CurrentDepth>();
87             Map<Integer, Integer> weights =
88                 (Map<Integer, Integer>)context.getProperty(
89                     "birthmarks.wsp.weights"
90                 );
91
92             int currentDepth = 0;
93             Integer forwardedStatus = null;
94             for(Opcode opcode: opcodes){
95                 if(opcode.getCategory() == Opcode.Category.TARGETER){
96                     forwardedStatus =
97                         tableMap.get(((LabelOpcode)opcode).getLabel());
98                 }
99                 else{
100                     WSPOpcode wspOpcode = new WSPOpcode(
101                         opcode, weights.get(opcode.getOpcode())
102                     );
103                     if(forwardedStatus == null){
104                         currentDepth += opcode.getAct();
105                     }
106                     else{
107                         currentDepth = forwardedStatus + opcode.getAct();
108                     }
109                     forwardedStatus = null;
110
111                     pattern.add(new CurrentDepth(currentDepth, wspOpcode));
112                     if(opcode.getCategory() == Opcode.Category.BRANCH){
113                         for(Label label: opcode.getLabels()){
114                             tableMap.put(label, currentDepth);
115                         }
116                     }
117                 }
118             }
119             return pattern;
120         }
121     }
122
123     @Override
124     public BirthmarkElement buildElement(String value){
125         return new StackPatternBasedBirthmarkElement(value);
126     };
127 }