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.dx.rop.code;
18 
19 import com.android.dx.rop.cst.Constant;
20 import com.android.dx.rop.cst.CstInteger;
21 import com.android.dx.rop.type.StdTypeList;
22 import com.android.dx.rop.type.Type;
23 import com.android.dx.rop.type.TypeBearer;
24 import com.android.dx.rop.type.TypeList;
25 
26 /**
27  * Plain instruction, which has no embedded data and which cannot possibly
28  * throw an exception.
29  */
30 public 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      */
PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result, RegisterSpecList sources)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("opcode with invalid branchingness: " + opcode.getBranchingness());
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      */
PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result, RegisterSpec source)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
getCatches()73     public TypeList getCatches() {
74         return StdTypeList.EMPTY;
75     }
76 
77     /** {@inheritDoc} */
78     @Override
accept(Visitor visitor)79     public void accept(Visitor visitor) {
80         visitor.visitPlainInsn(this);
81     }
82 
83     /** {@inheritDoc} */
84     @Override
withAddedCatch(Type type)85     public Insn withAddedCatch(Type type) {
86         throw new UnsupportedOperationException("unsupported");
87     }
88 
89     /** {@inheritDoc} */
90     @Override
withRegisterOffset(int delta)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
withSourceLiteral()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
withNewRegisters(RegisterSpec result, RegisterSpecList sources)149     public Insn withNewRegisters(RegisterSpec result,
150             RegisterSpecList sources) {
151 
152         return new PlainInsn(getOpcode(), getPosition(),
153                              result,
154                              sources);
155 
156     }
157 }
158