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