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