1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dexgen.dex.code;
18 
19 import com.android.dexgen.rop.code.RegisterSpecList;
20 import com.android.dexgen.rop.code.SourcePosition;
21 
22 /**
23  * Instruction which has a single branch target.
24  */
25 public final class TargetInsn extends FixedSizeInsn {
26     /** {@code non-null;} the branch target */
27     private CodeAddress target;
28 
29     /**
30      * Constructs an instance. The output address of this instance is initially
31      * unknown ({@code -1}), and the target is initially
32      * {@code null}.
33      *
34      * @param opcode the opcode; one of the constants from {@link Dops}
35      * @param position {@code non-null;} source position
36      * @param registers {@code non-null;} register list, including a
37      * result register if appropriate (that is, registers may be either
38      * ins or outs)
39      * @param target {@code non-null;} the branch target
40      */
TargetInsn(Dop opcode, SourcePosition position, RegisterSpecList registers, CodeAddress target)41     public TargetInsn(Dop opcode, SourcePosition position,
42                       RegisterSpecList registers, CodeAddress target) {
43         super(opcode, position, registers);
44 
45         if (target == null) {
46             throw new NullPointerException("target == null");
47         }
48 
49         this.target = target;
50     }
51 
52     /** {@inheritDoc} */
53     @Override
withOpcode(Dop opcode)54     public DalvInsn withOpcode(Dop opcode) {
55         return new TargetInsn(opcode, getPosition(), getRegisters(), target);
56     }
57 
58     /** {@inheritDoc} */
59     @Override
withRegisters(RegisterSpecList registers)60     public DalvInsn withRegisters(RegisterSpecList registers) {
61         return new TargetInsn(getOpcode(), getPosition(), registers, target);
62     }
63 
64     /**
65      * Returns an instance that is just like this one, except that its
66      * opcode has the opposite sense (as a test; e.g. a
67      * {@code lt} test becomes a {@code ge}), and its branch
68      * target is replaced by the one given, and all set-once values
69      * associated with the class (such as its address) are reset.
70      *
71      * @param target {@code non-null;} the new branch target
72      * @return {@code non-null;} an appropriately-constructed instance
73      */
withNewTargetAndReversed(CodeAddress target)74     public TargetInsn withNewTargetAndReversed(CodeAddress target) {
75         Dop opcode = getOpcode().getOppositeTest();
76 
77         return new TargetInsn(opcode, getPosition(), getRegisters(), target);
78     }
79 
80     /**
81      * Gets the unique branch target of this instruction.
82      *
83      * @return {@code non-null;} the branch target
84      */
getTarget()85     public CodeAddress getTarget() {
86         return target;
87     }
88 
89     /**
90      * Gets the target address of this instruction. This is only valid
91      * to call if the target instruction has been assigned an address,
92      * and it is merely a convenient shorthand for
93      * {@code getTarget().getAddress()}.
94      *
95      * @return {@code >= 0;} the target address
96      */
getTargetAddress()97     public int getTargetAddress() {
98         return target.getAddress();
99     }
100 
101     /**
102      * Gets the branch offset of this instruction. This is only valid to
103      * call if both this and the target instruction each has been assigned
104      * an address, and it is merely a convenient shorthand for
105      * {@code getTargetAddress() - getAddress()}.
106      *
107      * @return the branch offset
108      */
getTargetOffset()109     public int getTargetOffset() {
110         return target.getAddress() - getAddress();
111     }
112 
113     /**
114      * Returns whether the target offset is known.
115      *
116      * @return {@code true} if the target offset is known or
117      * {@code false} if not
118      */
hasTargetOffset()119     public boolean hasTargetOffset() {
120         return hasAddress() && target.hasAddress();
121     }
122 
123     /** {@inheritDoc} */
124     @Override
argString()125     protected String argString() {
126         if (target == null) {
127             return "????";
128         }
129 
130         return target.identifierString();
131     }
132 }
133