15ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver/*
25ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * Copyright 2013, Google Inc.
35ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * All rights reserved.
45ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *
55ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * Redistribution and use in source and binary forms, with or without
65ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * modification, are permitted provided that the following conditions are
75ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * met:
85ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *
95ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *     * Redistributions of source code must retain the above copyright
105ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * notice, this list of conditions and the following disclaimer.
115ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *     * Redistributions in binary form must reproduce the above
125ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * copyright notice, this list of conditions and the following disclaimer
135ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * in the documentation and/or other materials provided with the
145ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * distribution.
155ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *     * Neither the name of Google Inc. nor the names of its
165ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * contributors may be used to endorse or promote products derived from
175ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * this software without specific prior written permission.
185ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver *
195ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver */
315ff4ee9a3fc898dbe9a67386e984f14c21338391Ben Gruver
32766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruverpackage org.jf.dexlib2.builder;
33766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
34e80efa670f1027fdf3882a298216a460199e38d0Ben Gruverimport org.jf.dexlib2.iface.MethodImplementation;
35766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruverimport org.jf.dexlib2.iface.reference.StringReference;
36766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruverimport org.jf.dexlib2.iface.reference.TypeReference;
37766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
38766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruverimport javax.annotation.Nonnull;
39766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruverimport javax.annotation.Nullable;
40160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruverimport java.util.HashMap;
41766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
42e80efa670f1027fdf3882a298216a460199e38d0Ben Gruverpublic class MethodImplementationBuilder {
43160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    // Contains all named labels - both placed and unplaced
44bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    private final HashMap<String, Label> labels = new HashMap<String, Label>();
45160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
46160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    @Nonnull
47e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver    private final MutableMethodImplementation impl;
48160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
49897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver    private MethodLocation currentLocation;
50766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
51160449b83a0a19244ae27d0c9acf539c0c730be5Ben Gruver    public MethodImplementationBuilder(int registerCount) {
52160449b83a0a19244ae27d0c9acf539c0c730be5Ben Gruver        this.impl = new MutableMethodImplementation(registerCount);
53897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver        this.currentLocation = impl.instructionList.get(0);
54766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
55766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
56160449b83a0a19244ae27d0c9acf539c0c730be5Ben Gruver    public MethodImplementation getMethodImplementation() {
57160449b83a0a19244ae27d0c9acf539c0c730be5Ben Gruver        return impl;
58e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver    }
59e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver
60160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    /**
61160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * Adds a new named label at the current location.
62160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     *
63160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * Any previous unplaced references to a label of this name will now refer to this label/location
64160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     *
65160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * @param name The name of the label to add
66160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * @return A LabelRef representing the label
67160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     */
68766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    @Nonnull
69bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    public Label addLabel(@Nonnull String name) {
70bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver        Label label = labels.get(name);
71160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
72160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        if (label != null) {
73160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver            if (label.isPlaced()) {
74160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver                throw new IllegalArgumentException("There is already a label with that name.");
75160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver            } else {
76688611814ddff6babff935e81dcf51aff903563aBen Gruver                currentLocation.getLabels().add(label);
77160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver            }
78160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        } else {
79897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver            label = currentLocation.addNewLabel();
80160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver            labels.put(name, label);
81160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        }
82160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
83160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        return label;
84160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    }
85160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
86160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    /**
87160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * Get a reference to a label with the given name.
88160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     *
89160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * If a label with that name has not been added yet, a new one is created, but is left
90160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * in an unplaced state. It is assumed that addLabel(name) will be called at a later
91160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * point to define the location of the label.
92160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     *
93160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * @param name The name of the label to get
94160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     * @return A LabelRef representing the label
95160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver     */
96160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    @Nonnull
97bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    public Label getLabel(@Nonnull String name) {
98bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver        Label label = labels.get(name);
99160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        if (label == null) {
100bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver            label = new Label();
101160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver            labels.put(name, label);
102160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        }
103160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver        return label;
104766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
105766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
106bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    public void addCatch(@Nullable TypeReference type, @Nonnull Label from,
107bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver                         @Nonnull Label to, @Nonnull Label handler) {
108897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver        impl.addCatch(type, from, to, handler);
109160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver    }
110160fc1cdbabb1aafaadde1f8d872574b0666f1dcBen Gruver
111bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    public void addCatch(@Nullable String type, @Nonnull Label from, @Nonnull Label to,
112bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver                         @Nonnull Label handler) {
113897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver        impl.addCatch(type, from, to, handler);
114766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
115766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
116bb7937fd308738b46db61e5e6181dff3c8e6e19eBen Gruver    public void addCatch(@Nonnull Label from, @Nonnull Label to, @Nonnull Label handler) {
117897832aa150cdf53ed7fa2f17dee132d2408e2f3Ben Gruver        impl.addCatch(from, to, handler);
118766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
119766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
120766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addLineNumber(int lineNumber) {
121688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addLineNumber(lineNumber);
122766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
123766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
124766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addStartLocal(int registerNumber, @Nullable StringReference name, @Nullable TypeReference type,
125766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver                              @Nullable StringReference signature) {
126688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addStartLocal(registerNumber, name, type, signature);
127766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
128766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
129766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addEndLocal(int registerNumber) {
130688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addEndLocal(registerNumber);
131766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
132766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
133766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addRestartLocal(int registerNumber) {
134688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addRestartLocal(registerNumber);
135766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
136766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
137766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addPrologue() {
138688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addPrologue();
139766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
140766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
141766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    public void addEpilogue() {
142688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addEpilogue();
143766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
144766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
145263083faede803c028b2807b4abe761391bc3a98Ben Gruver    public void addSetSourceFile(@Nullable StringReference sourceFile) {
146688611814ddff6babff935e81dcf51aff903563aBen Gruver        currentLocation.addSetSourceFile(sourceFile);
147766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
148766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver
149e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver    public void addInstruction(@Nullable BuilderInstruction instruction) {
150e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver        impl.addInstruction(instruction);
151e80efa670f1027fdf3882a298216a460199e38d0Ben Gruver        currentLocation = impl.instructionList.get(impl.instructionList.size()-1);
152766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver    }
153766f285a70af96d09c3cd1d47fce5f9c76bbb616Ben Gruver}
154