PlainInsn.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
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
17package com.android.dx.rop.code;
18
19import com.android.dx.rop.type.StdTypeList;
20import com.android.dx.rop.type.Type;
21import com.android.dx.rop.type.TypeList;
22import com.android.dx.rop.type.TypeBearer;
23import com.android.dx.rop.cst.Constant;
24import com.android.dx.rop.cst.CstInteger;
25
26/**
27 * Plain instruction, which has no embedded data and which cannot possibly
28 * throw an exception.
29 */
30public final class PlainInsn
31        extends Insn {
32    /**
33     * Constructs an instance.
34     *
35     * @param opcode {@code non-null;} the opcode
36     * @param position {@code non-null;} source position
37     * @param result {@code null-ok;} spec for the result, if any
38     * @param sources {@code non-null;} specs for all the sources
39     */
40    public PlainInsn(Rop opcode, SourcePosition position,
41                     RegisterSpec result, RegisterSpecList sources) {
42        super(opcode, position, result, sources);
43
44        switch (opcode.getBranchingness()) {
45            case Rop.BRANCH_SWITCH:
46            case Rop.BRANCH_THROW: {
47                throw new IllegalArgumentException("bogus branchingness");
48            }
49        }
50
51        if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
52            // move-result-pseudo is required here
53            throw new IllegalArgumentException
54                    ("can't mix branchingness with result");
55        }
56    }
57
58    /**
59     * Constructs a single-source instance.
60     *
61     * @param opcode {@code non-null;} the opcode
62     * @param position {@code non-null;} source position
63     * @param result {@code null-ok;} spec for the result, if any
64     * @param source {@code non-null;} spec for the source
65     */
66    public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
67                     RegisterSpec source) {
68        this(opcode, position, result, RegisterSpecList.make(source));
69    }
70
71    /** {@inheritDoc} */
72    @Override
73    public TypeList getCatches() {
74        return StdTypeList.EMPTY;
75    }
76
77    /** {@inheritDoc} */
78    @Override
79    public void accept(Visitor visitor) {
80        visitor.visitPlainInsn(this);
81    }
82
83    /** {@inheritDoc} */
84    @Override
85    public Insn withAddedCatch(Type type) {
86        throw new UnsupportedOperationException("unsupported");
87    }
88
89    /** {@inheritDoc} */
90    @Override
91    public Insn withRegisterOffset(int delta) {
92        return new PlainInsn(getOpcode(), getPosition(),
93                             getResult().withOffset(delta),
94                             getSources().withOffset(delta));
95    }
96
97    /** {@inheritDoc} */
98    @Override
99    public Insn withSourceLiteral() {
100        RegisterSpecList sources = getSources();
101        int szSources = sources.size();
102
103        if (szSources == 0) {
104            return this;
105        }
106
107        TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
108
109        if (!lastType.isConstant()) {
110            // Check for reverse subtraction, where first source is constant
111            TypeBearer firstType = sources.get(0).getTypeBearer();
112            if (szSources == 2 && firstType.isConstant()) {
113                Constant cst = (Constant) firstType;
114                RegisterSpecList newSources = sources.withoutFirst();
115                Rop newRop = Rops.ropFor(getOpcode().getOpcode(), getResult(),
116                                             newSources, cst);
117                return new PlainCstInsn(newRop, getPosition(), getResult(),
118                                            newSources, cst);
119            }
120            return this;
121        } else {
122
123            Constant cst = (Constant) lastType;
124
125            RegisterSpecList newSources = sources.withoutLast();
126
127            Rop newRop;
128            try {
129                // Check for constant subtraction and flip it to be addition
130                int opcode = getOpcode().getOpcode();
131                if (opcode == RegOps.SUB && cst instanceof CstInteger) {
132                    opcode = RegOps.ADD;
133                    cst = CstInteger.make(-((CstInteger)cst).getValue());
134                }
135                newRop = Rops.ropFor(opcode, getResult(), newSources, cst);
136            } catch (IllegalArgumentException ex) {
137                // There's no rop for this case
138                return this;
139            }
140
141            return new PlainCstInsn(newRop, getPosition(),
142                    getResult(), newSources, cst);
143        }
144    }
145
146
147    /** {@inheritDoc} */
148    @Override
149    public Insn withNewRegisters(RegisterSpec result,
150            RegisterSpecList sources) {
151
152        return new PlainInsn(getOpcode(), getPosition(),
153                             result,
154                             sources);
155
156    }
157}
158