1 /*
2  * Copyright 2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.dexlib2.builder;
33 
34 import org.jf.dexlib2.iface.MethodImplementation;
35 import org.jf.dexlib2.iface.reference.StringReference;
36 import org.jf.dexlib2.iface.reference.TypeReference;
37 
38 import javax.annotation.Nonnull;
39 import javax.annotation.Nullable;
40 import java.util.HashMap;
41 
42 public class MethodImplementationBuilder {
43     // Contains all named labels - both placed and unplaced
44     private final HashMap<String, Label> labels = new HashMap<String, Label>();
45 
46     @Nonnull
47     private final MutableMethodImplementation impl;
48 
49     private MethodLocation currentLocation;
50 
MethodImplementationBuilder(int registerCount)51     public MethodImplementationBuilder(int registerCount) {
52         this.impl = new MutableMethodImplementation(registerCount);
53         this.currentLocation = impl.instructionList.get(0);
54     }
55 
getMethodImplementation()56     public MethodImplementation getMethodImplementation() {
57         return impl;
58     }
59 
60     /**
61      * Adds a new named label at the current location.
62      *
63      * Any previous unplaced references to a label of this name will now refer to this label/location
64      *
65      * @param name The name of the label to add
66      * @return A LabelRef representing the label
67      */
68     @Nonnull
addLabel(@onnull String name)69     public Label addLabel(@Nonnull String name) {
70         Label label = labels.get(name);
71 
72         if (label != null) {
73             if (label.isPlaced()) {
74                 throw new IllegalArgumentException("There is already a label with that name.");
75             } else {
76                 currentLocation.getLabels().add(label);
77             }
78         } else {
79             label = currentLocation.addNewLabel();
80             labels.put(name, label);
81         }
82 
83         return label;
84     }
85 
86     /**
87      * Get a reference to a label with the given name.
88      *
89      * If a label with that name has not been added yet, a new one is created, but is left
90      * in an unplaced state. It is assumed that addLabel(name) will be called at a later
91      * point to define the location of the label.
92      *
93      * @param name The name of the label to get
94      * @return A LabelRef representing the label
95      */
96     @Nonnull
getLabel(@onnull String name)97     public Label getLabel(@Nonnull String name) {
98         Label label = labels.get(name);
99         if (label == null) {
100             label = new Label();
101             labels.put(name, label);
102         }
103         return label;
104     }
105 
addCatch(@ullable TypeReference type, @Nonnull Label from, @Nonnull Label to, @Nonnull Label handler)106     public void addCatch(@Nullable TypeReference type, @Nonnull Label from,
107                          @Nonnull Label to, @Nonnull Label handler) {
108         impl.addCatch(type, from, to, handler);
109     }
110 
addCatch(@ullable String type, @Nonnull Label from, @Nonnull Label to, @Nonnull Label handler)111     public void addCatch(@Nullable String type, @Nonnull Label from, @Nonnull Label to,
112                          @Nonnull Label handler) {
113         impl.addCatch(type, from, to, handler);
114     }
115 
addCatch(@onnull Label from, @Nonnull Label to, @Nonnull Label handler)116     public void addCatch(@Nonnull Label from, @Nonnull Label to, @Nonnull Label handler) {
117         impl.addCatch(from, to, handler);
118     }
119 
addLineNumber(int lineNumber)120     public void addLineNumber(int lineNumber) {
121         currentLocation.addLineNumber(lineNumber);
122     }
123 
addStartLocal(int registerNumber, @Nullable StringReference name, @Nullable TypeReference type, @Nullable StringReference signature)124     public void addStartLocal(int registerNumber, @Nullable StringReference name, @Nullable TypeReference type,
125                               @Nullable StringReference signature) {
126         currentLocation.addStartLocal(registerNumber, name, type, signature);
127     }
128 
addEndLocal(int registerNumber)129     public void addEndLocal(int registerNumber) {
130         currentLocation.addEndLocal(registerNumber);
131     }
132 
addRestartLocal(int registerNumber)133     public void addRestartLocal(int registerNumber) {
134         currentLocation.addRestartLocal(registerNumber);
135     }
136 
addPrologue()137     public void addPrologue() {
138         currentLocation.addPrologue();
139     }
140 
addEpilogue()141     public void addEpilogue() {
142         currentLocation.addEpilogue();
143     }
144 
addSetSourceFile(@ullable StringReference sourceFile)145     public void addSetSourceFile(@Nullable StringReference sourceFile) {
146         currentLocation.addSetSourceFile(sourceFile);
147     }
148 
addInstruction(@ullable BuilderInstruction instruction)149     public void addInstruction(@Nullable BuilderInstruction instruction) {
150         impl.addInstruction(instruction);
151         currentLocation = impl.instructionList.get(impl.instructionList.size()-1);
152     }
153 }
154