Home | History | Annotate | Download | only in ragel
      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 
     32 package org.jf.dexlib2.util;
     33 
     34 import org.jf.dexlib2.iface.instruction.Instruction;
     35 import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
     36 import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
     37 import org.jf.dexlib2.Opcodes;
     38 
     39 import java.util.List;
     40 
     41 public 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 }