summaryrefslogtreecommitdiff
path: root/dx/src/com/android/dx/dex/code/TargetInsn.java
blob: cbb5ff9a60617d0536d3651d7b61a33c9b642393 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dx.dex.code;

import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.code.SourcePosition;

/**
 * Instruction which has a single branch target.
 */
public final class TargetInsn extends FixedSizeInsn {
    /** {@code non-null;} the branch target */
    private CodeAddress target;

    /**
     * Constructs an instance. The output address of this instance is initially
     * unknown ({@code -1}), and the target is initially
     * {@code null}.
     *
     * @param opcode the opcode; one of the constants from {@link Dops}
     * @param position {@code non-null;} source position
     * @param registers {@code non-null;} register list, including a
     * result register if appropriate (that is, registers may be either
     * ins or outs)
     * @param target {@code non-null;} the branch target
     */
    public TargetInsn(Dop opcode, SourcePosition position,
                      RegisterSpecList registers, CodeAddress target) {
        super(opcode, position, registers);

        if (target == null) {
            throw new NullPointerException("target == null");
        }

        this.target = target;
    }

    /** {@inheritDoc} */
    @Override
    public DalvInsn withOpcode(Dop opcode) {
        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
    }

    /** {@inheritDoc} */
    @Override
    public DalvInsn withRegisters(RegisterSpecList registers) {
        return new TargetInsn(getOpcode(), getPosition(), registers, target);
    }

    /**
     * Returns an instance that is just like this one, except that its
     * opcode has the opposite sense (as a test; e.g. a
     * {@code lt} test becomes a {@code ge}), and its branch
     * target is replaced by the one given, and all set-once values
     * associated with the class (such as its address) are reset.
     *
     * @param target {@code non-null;} the new branch target
     * @return {@code non-null;} an appropriately-constructed instance
     */
    public TargetInsn withNewTargetAndReversed(CodeAddress target) {
        Dop opcode = getOpcode().getOppositeTest();

        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
    }

    /**
     * Gets the unique branch target of this instruction.
     *
     * @return {@code non-null;} the branch target
     */
    public CodeAddress getTarget() {
        return target;
    }

    /**
     * Gets the target address of this instruction. This is only valid
     * to call if the target instruction has been assigned an address,
     * and it is merely a convenient shorthand for
     * {@code getTarget().getAddress()}.
     *
     * @return {@code >= 0;} the target address
     */
    public int getTargetAddress() {
        return target.getAddress();
    }

    /**
     * Gets the branch offset of this instruction. This is only valid to
     * call if both this and the target instruction each has been assigned
     * an address, and it is merely a convenient shorthand for
     * {@code getTargetAddress() - getAddress()}.
     *
     * @return the branch offset
     */
    public int getTargetOffset() {
        return target.getAddress() - getAddress();
    }

    /**
     * Returns whether the target offset is known.
     *
     * @return {@code true} if the target offset is known or
     * {@code false} if not
     */
    public boolean hasTargetOffset() {
        return hasAddress() && target.hasAddress();
    }

    /** {@inheritDoc} */
    @Override
    protected String argString() {
        if (target == null) {
            return "????";
        }

        return target.identifierString();
    }
}