| /* |
| * Copyright 2012, Google Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package org.jf.dexlib2.util; |
| |
| import org.jf.dexlib2.iface.instruction.Instruction; |
| import org.jf.dexlib2.iface.instruction.OneRegisterInstruction; |
| import org.jf.dexlib2.iface.instruction.WideLiteralInstruction; |
| |
| import java.util.List; |
| |
| public class SyntheticAccessorFSM { |
| %% machine SyntheticAccessorFSM; |
| %% write data; |
| |
| // math type constants |
| public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT; |
| public static final int SUB = SyntheticAccessorResolver.SUB_ASSIGNMENT; |
| public static final int MUL = SyntheticAccessorResolver.MUL_ASSIGNMENT; |
| public static final int DIV = SyntheticAccessorResolver.DIV_ASSIGNMENT; |
| public static final int REM = SyntheticAccessorResolver.REM_ASSIGNMENT; |
| public static final int AND = SyntheticAccessorResolver.AND_ASSIGNMENT; |
| public static final int OR = SyntheticAccessorResolver.OR_ASSIGNMENT; |
| public static final int XOR = SyntheticAccessorResolver.XOR_ASSIGNMENT; |
| public static final int SHL = SyntheticAccessorResolver.SHL_ASSIGNMENT; |
| public static final int SHR = SyntheticAccessorResolver.SHR_ASSIGNMENT; |
| public static final int USHR = SyntheticAccessorResolver.USHR_ASSIGNMENT; |
| |
| public static final int INT = 0; |
| public static final int LONG = 1; |
| public static final int FLOAT = 2; |
| public static final int DOUBLE = 3; |
| |
| public static final int POSITIVE_ONE = 1; |
| public static final int NEGATIVE_ONE = -1; |
| public static final int OTHER = 0; |
| |
| public static int test(List<? extends Instruction> instructions) { |
| int accessorType = -1; |
| int cs, p = 0; |
| int pe = instructions.size(); |
| |
| // one of the math type constants representing the type of math operation being performed |
| int mathOp = -1; |
| |
| // for increments an decrements, the type of value the math operation is on |
| int mathType = -1; |
| |
| // for increments and decrements, the value of the constant that is used |
| long constantValue = 0; |
| |
| // The source register for the put instruction |
| int putRegister = -1; |
| // The return register; |
| int returnRegister = -1; |
| |
| %%{ |
| import "Opcodes.rl"; |
| alphtype short; |
| getkey instructions.get(p).getOpcode().value; |
| |
| get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets |
| |
| # all iputs/sputs |
| put = ((0x59 .. 0x5f) | (0x67 .. 0x6d)) @ { |
| putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA(); |
| }; |
| |
| invoke = (0x6e .. 0x72) | (0x74 .. 0x78); # all invokes |
| |
| # all numeric const instructions |
| const_literal = (0x12 .. 0x19) @ { |
| constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral(); |
| }; |
| |
| add_const = (add_int_lit8 | add_int_lit16) @ { |
| mathType = INT; |
| mathOp = ADD; |
| constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral(); |
| }; |
| |
| arbitrary_add = (((add_int | add_int_2addr) @ { mathType = INT; }) | |
| ((add_long | add_long_2addr) @ { mathType = LONG; }) | |
| ((add_float | add_float_2addr) @ { mathType = FLOAT; }) | |
| ((add_double | add_double_2addr) @ {mathType = DOUBLE; })) @ { |
| mathOp = ADD; |
| }; |
| arbitrary_sub = (((sub_int | sub_int_2addr) @ { mathType = INT; }) | |
| ((sub_long | sub_long_2addr) @ { mathType = LONG; }) | |
| ((sub_float | sub_float_2addr) @ { mathType = FLOAT; }) | |
| ((sub_double | sub_double_2addr) @ {mathType = DOUBLE; })) @ { |
| mathOp = SUB; |
| }; |
| arbitrary_mul = (mul_int | mul_int_2addr | mul_long | mul_long_2addr | |
| mul_float | mul_float_2addr | mul_double | mul_double_2addr) @ { |
| mathOp = MUL; |
| }; |
| arbitrary_div = (div_int | div_int_2addr | div_long | div_long_2addr | |
| div_float | div_float_2addr | div_double | div_double_2addr) @ { |
| mathOp = DIV; |
| }; |
| arbitrary_rem = (rem_int | rem_int_2addr | rem_long | rem_long_2addr | |
| rem_float | rem_float_2addr | rem_double | rem_double_2addr) @ { |
| mathOp = REM; |
| }; |
| arbitrary_and = (and_int | and_int_2addr | and_long | and_long_2addr) @ { |
| mathOp = AND; |
| }; |
| arbitrary_or = (or_int | or_int_2addr | or_long | or_long_2addr) @ { |
| mathOp = OR; |
| }; |
| arbitrary_xor = (xor_int | xor_int_2addr | xor_long | xor_long_2addr) @ { |
| mathOp = XOR; |
| }; |
| arbitrary_shl = (shl_int | shl_int_2addr | shl_long | shl_long_2addr) @ { |
| mathOp = SHL; |
| }; |
| arbitrary_shr = (shr_int | shr_int_2addr | shr_long | shr_long_2addr) @ { |
| mathOp = SHR; |
| }; |
| arbitrary_ushr = (ushr_int | ushr_int_2addr | ushr_long | ushr_long_2addr) @ { |
| mathOp = USHR; |
| }; |
| |
| type_conversion = 0x81 .. 0x8f; # all type-conversion opcodes |
| |
| return_something = (return | return_wide | return_object) @ { |
| returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA(); |
| }; |
| |
| any_move_result = move_result | move_result_wide | move_result_object; |
| |
| get_accessor = get return_something @ { |
| accessorType = SyntheticAccessorResolver.GETTER; fbreak; |
| }; |
| |
| put_accessor = put return_something @ { |
| accessorType = SyntheticAccessorResolver.SETTER; fbreak; |
| }; |
| |
| invoke_accessor = invoke (return_void | (any_move_result return_something)) @ { |
| accessorType = SyntheticAccessorResolver.METHOD; fbreak; |
| }; |
| |
| increment_accessor = get add_const type_conversion? put return_something @ { |
| accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister); |
| }; |
| |
| alt_increment_accessor = get const_literal (arbitrary_add | arbitrary_sub) put return_something @ { |
| accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister); |
| }; |
| |
| math_assignment_accessor = get type_conversion? |
| (arbitrary_add | arbitrary_sub | arbitrary_mul | arbitrary_div | arbitrary_rem | |
| arbitrary_and | arbitrary_or | arbitrary_xor | arbitrary_shl | arbitrary_shr | |
| arbitrary_ushr) |
| type_conversion{0,2} put return_something @ { |
| accessorType = mathOp; fbreak; |
| }; |
| |
| main := get_accessor | |
| put_accessor | |
| invoke_accessor | |
| increment_accessor | |
| alt_increment_accessor | |
| math_assignment_accessor; |
| |
| write init; |
| write exec; |
| }%% |
| |
| return accessorType; |
| } |
| |
| private static int getIncrementType(int mathOp, int mathType, long constantValue, int putRegister, |
| int returnRegister) { |
| boolean isPrefix = putRegister == returnRegister; |
| |
| boolean negativeConstant = false; |
| |
| switch (mathType) { |
| case INT: |
| case LONG: { |
| if (constantValue == 1) { |
| negativeConstant = false; |
| } else if (constantValue == -1) { |
| negativeConstant = true; |
| } else { |
| return -1; |
| } |
| break; |
| } |
| case FLOAT: { |
| float val = Float.intBitsToFloat((int)constantValue); |
| if (val == 1) { |
| negativeConstant = false; |
| } else if (val == -1) { |
| negativeConstant = true; |
| } else { |
| return -1; |
| } |
| break; |
| } |
| case DOUBLE: { |
| double val = Double.longBitsToDouble(constantValue); |
| if (val == 1) { |
| negativeConstant = false; |
| } else if (val == -1) { |
| negativeConstant = true; |
| } else { |
| return -1; |
| } |
| break; |
| } |
| } |
| |
| boolean isAdd = ((mathOp == ADD) && !negativeConstant) || |
| ((mathOp == SUB) && negativeConstant); |
| |
| if (isPrefix) { |
| if (isAdd) { |
| return SyntheticAccessorResolver.PREFIX_INCREMENT; |
| } else { |
| return SyntheticAccessorResolver.PREFIX_DECREMENT; |
| } |
| } else { |
| if (isAdd) { |
| return SyntheticAccessorResolver.POSTFIX_INCREMENT; |
| } else { |
| return SyntheticAccessorResolver.POSTFIX_DECREMENT; |
| } |
| } |
| } |
| } |