xref: /aosp_15_r20/external/google-smali/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl (revision 37f5703ca959d1ce24046e7595880d209e15c133)
1/*
2 * Copyright 2012, Google LLC
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google LLC nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31package com.android.tools.smali.dexlib2.util;
32
33import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
34import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction;
35import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction;
36import com.android.tools.smali.dexlib2.Opcodes;
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    @Nonnull private final Opcodes opcodes;
67
68    public SyntheticAccessorFSM(@Nonnull Opcodes opcodes) {
69        this.opcodes = opcodes;
70    }
71
72    public int test(List<? extends Instruction> instructions) {
73        int accessorType = -1;
74        int cs, p = 0;
75        int pe = instructions.size();
76
77        // one of the math type constants representing the type of math operation being performed
78        int mathOp = -1;
79
80        // for increments an decrements, the type of value the math operation is on
81        int mathType = -1;
82
83        // for increments and decrements, the value of the constant that is used
84        long constantValue = 0;
85
86        // The source register for the put instruction
87        int putRegister = -1;
88        // The return register;
89        int returnRegister = -1;
90
91        %%{
92            import "Opcodes.rl";
93            alphtype short;
94            getkey opcodes.getOpcodeValue(instructions.get(p).getOpcode());
95
96            get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets
97
98            # all iputs/sputs
99            put = ((0x59 .. 0x5f) | (0x67 .. 0x6d)) @ {
100                putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
101            };
102
103            invoke = (0x6e .. 0x72) | (0x74 .. 0x78); # all invokes
104
105            # all numeric const instructions
106            const_literal = (0x12 .. 0x19) @ {
107                constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
108            };
109
110            add_const = (add_int_lit8 | add_int_lit16) @ {
111                mathType = INT;
112                mathOp = ADD;
113                constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
114            };
115
116            arbitrary_add = (((add_int | add_int_2addr) @ { mathType = INT; }) |
117                             ((add_long | add_long_2addr) @ { mathType = LONG; }) |
118                             ((add_float | add_float_2addr) @ { mathType = FLOAT; }) |
119                             ((add_double | add_double_2addr) @ {mathType = DOUBLE; })) @ {
120                mathOp = ADD;
121            };
122            arbitrary_sub = (((sub_int | sub_int_2addr) @ { mathType = INT; }) |
123                             ((sub_long | sub_long_2addr) @ { mathType = LONG; }) |
124                             ((sub_float | sub_float_2addr) @ { mathType = FLOAT; }) |
125                             ((sub_double | sub_double_2addr) @ {mathType = DOUBLE; })) @ {
126                mathOp = SUB;
127            };
128            arbitrary_mul = (mul_int | mul_int_2addr | mul_long | mul_long_2addr |
129                            mul_float | mul_float_2addr | mul_double | mul_double_2addr) @ {
130                mathOp = MUL;
131            };
132            arbitrary_div = (div_int | div_int_2addr | div_long | div_long_2addr |
133                            div_float | div_float_2addr | div_double | div_double_2addr) @ {
134                mathOp = DIV;
135            };
136            arbitrary_rem = (rem_int | rem_int_2addr | rem_long | rem_long_2addr |
137                            rem_float | rem_float_2addr | rem_double | rem_double_2addr) @ {
138                mathOp = REM;
139            };
140            arbitrary_and = (and_int | and_int_2addr | and_long | and_long_2addr) @ {
141                mathOp = AND;
142            };
143            arbitrary_or = (or_int | or_int_2addr | or_long | or_long_2addr) @ {
144                mathOp = OR;
145            };
146            arbitrary_xor = (xor_int | xor_int_2addr | xor_long | xor_long_2addr) @ {
147                mathOp = XOR;
148            };
149            arbitrary_shl = (shl_int | shl_int_2addr | shl_long | shl_long_2addr) @ {
150                mathOp = SHL;
151            };
152            arbitrary_shr = (shr_int | shr_int_2addr | shr_long | shr_long_2addr) @ {
153                mathOp = SHR;
154            };
155            arbitrary_ushr = (ushr_int | ushr_int_2addr | ushr_long | ushr_long_2addr) @ {
156                mathOp = USHR;
157            };
158
159            type_conversion = 0x81 .. 0x8f; # all type-conversion opcodes
160
161            return_something = (return | return_wide | return_object) @ {
162                returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
163            };
164
165            any_move_result = move_result | move_result_wide | move_result_object;
166
167            get_accessor = get return_something @ {
168                accessorType = SyntheticAccessorResolver.GETTER; fbreak;
169            };
170
171            put_accessor = put return_something @ {
172                accessorType = SyntheticAccessorResolver.SETTER; fbreak;
173            };
174
175            invoke_accessor = invoke (return_void | (any_move_result return_something)) @ {
176                accessorType = SyntheticAccessorResolver.METHOD; fbreak;
177            };
178
179            increment_accessor = get add_const type_conversion? put return_something @ {
180                accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
181            };
182
183            alt_increment_accessor = get const_literal (arbitrary_add | arbitrary_sub) put return_something @ {
184                accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
185            };
186
187            math_assignment_accessor = get type_conversion?
188                                       (arbitrary_add | arbitrary_sub | arbitrary_mul | arbitrary_div | arbitrary_rem |
189                                        arbitrary_and | arbitrary_or | arbitrary_xor | arbitrary_shl | arbitrary_shr |
190                                        arbitrary_ushr)
191                                        type_conversion{0,2} put return_something @ {
192                accessorType = mathOp; fbreak;
193            };
194
195            main := get_accessor |
196                    put_accessor |
197                    invoke_accessor |
198                    increment_accessor |
199                    alt_increment_accessor |
200                    math_assignment_accessor;
201
202            write init;
203            write exec;
204        }%%
205
206        return accessorType;
207    }
208
209    private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister,
210            int returnRegister) {
211        boolean isPrefix = putRegister == returnRegister;
212
213        boolean negativeConstant = false;
214
215        switch (mathType) {
216            case INT:
217            case LONG: {
218                if (constantValue == 1) {
219                    negativeConstant = false;
220                } else if (constantValue == -1) {
221                    negativeConstant = true;
222                } else {
223                    return -1;
224                }
225                break;
226            }
227            case FLOAT: {
228                float val = Float.intBitsToFloat((int)constantValue);
229                if (val == 1) {
230                    negativeConstant = false;
231                } else if (val == -1) {
232                    negativeConstant = true;
233                } else {
234                    return -1;
235                }
236                break;
237            }
238            case DOUBLE: {
239                double val = Double.longBitsToDouble(constantValue);
240                if (val == 1) {
241                    negativeConstant = false;
242                } else if (val == -1) {
243                    negativeConstant = true;
244                } else {
245                    return -1;
246                }
247                break;
248            }
249        }
250
251        boolean isAdd = ((mathOp == ADD) && !negativeConstant) ||
252                        ((mathOp == SUB) && negativeConstant);
253
254        if (isPrefix) {
255            if (isAdd) {
256                return SyntheticAccessorResolver.PREFIX_INCREMENT;
257            } else {
258                return SyntheticAccessorResolver.PREFIX_DECREMENT;
259            }
260        } else {
261            if (isAdd) {
262                return SyntheticAccessorResolver.POSTFIX_INCREMENT;
263            } else {
264                return SyntheticAccessorResolver.POSTFIX_DECREMENT;
265            }
266        }
267    }
268}