1/*
2 * Copyright 2012, 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
32package org.jf.dexlib2.util;
33
34import org.jf.dexlib2.iface.instruction.Instruction;
35import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
36import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
37
38import java.util.List;
39
40public class SyntheticAccessorFSM {
41    %% machine SyntheticAccessorFSM;
42    %% write data;
43
44    // math type constants
45    public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT;
46    public static final int SUB = SyntheticAccessorResolver.SUB_ASSIGNMENT;
47    public static final int MUL = SyntheticAccessorResolver.MUL_ASSIGNMENT;
48    public static final int DIV = SyntheticAccessorResolver.DIV_ASSIGNMENT;
49    public static final int REM = SyntheticAccessorResolver.REM_ASSIGNMENT;
50    public static final int AND = SyntheticAccessorResolver.AND_ASSIGNMENT;
51    public static final int OR = SyntheticAccessorResolver.OR_ASSIGNMENT;
52    public static final int XOR = SyntheticAccessorResolver.XOR_ASSIGNMENT;
53    public static final int SHL = SyntheticAccessorResolver.SHL_ASSIGNMENT;
54    public static final int SHR = SyntheticAccessorResolver.SHR_ASSIGNMENT;
55    public static final int USHR = SyntheticAccessorResolver.USHR_ASSIGNMENT;
56
57    public static final int INT = 0;
58    public static final int LONG = 1;
59    public static final int FLOAT = 2;
60    public static final int DOUBLE = 3;
61
62    public static final int POSITIVE_ONE = 1;
63    public static final int NEGATIVE_ONE = -1;
64    public static final int OTHER = 0;
65
66    public static int test(List<? extends Instruction> instructions) {
67        int accessorType = -1;
68        int cs, p = 0;
69        int pe = instructions.size();
70
71        // one of the math type constants representing the type of math operation being performed
72        int mathOp = -1;
73
74        // for increments an decrements, the type of value the math operation is on
75        int mathType = -1;
76
77        // for increments and decrements, the value of the constant that is used
78        long constantValue = 0;
79
80        // The source register for the put instruction
81        int putRegister = -1;
82        // The return register;
83        int returnRegister = -1;
84
85        %%{
86            import "Opcodes.rl";
87            alphtype short;
88            getkey instructions.get(p).getOpcode().value;
89
90            get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets
91
92            # all iputs/sputs
93            put = ((0x59 .. 0x5f) | (0x67 .. 0x6d)) @ {
94                putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
95            };
96
97            invoke = (0x6e .. 0x72) | (0x74 .. 0x78); # all invokes
98
99            # all numeric const instructions
100            const_literal = (0x12 .. 0x19) @ {
101                constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
102            };
103
104            add_const = (add_int_lit8 | add_int_lit16) @ {
105                mathType = INT;
106                mathOp = ADD;
107                constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
108            };
109
110            arbitrary_add = (((add_int | add_int_2addr) @ { mathType = INT; }) |
111                             ((add_long | add_long_2addr) @ { mathType = LONG; }) |
112                             ((add_float | add_float_2addr) @ { mathType = FLOAT; }) |
113                             ((add_double | add_double_2addr) @ {mathType = DOUBLE; })) @ {
114                mathOp = ADD;
115            };
116            arbitrary_sub = (((sub_int | sub_int_2addr) @ { mathType = INT; }) |
117                             ((sub_long | sub_long_2addr) @ { mathType = LONG; }) |
118                             ((sub_float | sub_float_2addr) @ { mathType = FLOAT; }) |
119                             ((sub_double | sub_double_2addr) @ {mathType = DOUBLE; })) @ {
120                mathOp = SUB;
121            };
122            arbitrary_mul = (mul_int | mul_int_2addr | mul_long | mul_long_2addr |
123                            mul_float | mul_float_2addr | mul_double | mul_double_2addr) @ {
124                mathOp = MUL;
125            };
126            arbitrary_div = (div_int | div_int_2addr | div_long | div_long_2addr |
127                            div_float | div_float_2addr | div_double | div_double_2addr) @ {
128                mathOp = DIV;
129            };
130            arbitrary_rem = (rem_int | rem_int_2addr | rem_long | rem_long_2addr |
131                            rem_float | rem_float_2addr | rem_double | rem_double_2addr) @ {
132                mathOp = REM;
133            };
134            arbitrary_and = (and_int | and_int_2addr | and_long | and_long_2addr) @ {
135                mathOp = AND;
136            };
137            arbitrary_or = (or_int | or_int_2addr | or_long | or_long_2addr) @ {
138                mathOp = OR;
139            };
140            arbitrary_xor = (xor_int | xor_int_2addr | xor_long | xor_long_2addr) @ {
141                mathOp = XOR;
142            };
143            arbitrary_shl = (shl_int | shl_int_2addr | shl_long | shl_long_2addr) @ {
144                mathOp = SHL;
145            };
146            arbitrary_shr = (shr_int | shr_int_2addr | shr_long | shr_long_2addr) @ {
147                mathOp = SHR;
148            };
149            arbitrary_ushr = (ushr_int | ushr_int_2addr | ushr_long | ushr_long_2addr) @ {
150                mathOp = USHR;
151            };
152
153            type_conversion = 0x81 .. 0x8f; # all type-conversion opcodes
154
155            return_something = (return | return_wide | return_object) @ {
156                returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
157            };
158
159            any_move_result = move_result | move_result_wide | move_result_object;
160
161            get_accessor = get return_something @ {
162                accessorType = SyntheticAccessorResolver.GETTER; fbreak;
163            };
164
165            put_accessor = put return_something @ {
166                accessorType = SyntheticAccessorResolver.SETTER; fbreak;
167            };
168
169            invoke_accessor = invoke (return_void | (any_move_result return_something)) @ {
170                accessorType = SyntheticAccessorResolver.METHOD; fbreak;
171            };
172
173            increment_accessor = get add_const type_conversion? put return_something @ {
174                accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
175            };
176
177            alt_increment_accessor = get const_literal (arbitrary_add | arbitrary_sub) put return_something @ {
178                accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
179            };
180
181            math_assignment_accessor = get type_conversion?
182                                       (arbitrary_add | arbitrary_sub | arbitrary_mul | arbitrary_div | arbitrary_rem |
183                                        arbitrary_and | arbitrary_or | arbitrary_xor | arbitrary_shl | arbitrary_shr |
184                                        arbitrary_ushr)
185                                        type_conversion{0,2} put return_something @ {
186                accessorType = mathOp; fbreak;
187            };
188
189            main := get_accessor |
190                    put_accessor |
191                    invoke_accessor |
192                    increment_accessor |
193                    alt_increment_accessor |
194                    math_assignment_accessor;
195
196            write init;
197            write exec;
198        }%%
199
200        return accessorType;
201    }
202
203    private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister,
204            int returnRegister) {
205        boolean isPrefix = putRegister == returnRegister;
206
207        boolean negativeConstant = false;
208
209        switch (mathType) {
210            case INT:
211            case LONG: {
212                if (constantValue == 1) {
213                    negativeConstant = false;
214                } else if (constantValue == -1) {
215                    negativeConstant = true;
216                } else {
217                    return -1;
218                }
219                break;
220            }
221            case FLOAT: {
222                float val = Float.intBitsToFloat((int)constantValue);
223                if (val == 1) {
224                    negativeConstant = false;
225                } else if (val == -1) {
226                    negativeConstant = true;
227                } else {
228                    return -1;
229                }
230                break;
231            }
232            case DOUBLE: {
233                double val = Double.longBitsToDouble(constantValue);
234                if (val == 1) {
235                    negativeConstant = false;
236                } else if (val == -1) {
237                    negativeConstant = true;
238                } else {
239                    return -1;
240                }
241                break;
242            }
243        }
244
245        boolean isAdd = ((mathOp == ADD) && !negativeConstant) ||
246                        ((mathOp == SUB) && negativeConstant);
247
248        if (isPrefix) {
249            if (isAdd) {
250                return SyntheticAccessorResolver.PREFIX_INCREMENT;
251            } else {
252                return SyntheticAccessorResolver.PREFIX_DECREMENT;
253            }
254        } else {
255            if (isAdd) {
256                return SyntheticAccessorResolver.POSTFIX_INCREMENT;
257            } else {
258                return SyntheticAccessorResolver.POSTFIX_DECREMENT;
259            }
260        }
261    }
262}