1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/* 2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project 3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License"); 5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License. 6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at 7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * http://www.apache.org/licenses/LICENSE-2.0 9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software 11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS, 12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and 14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License. 15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.code; 18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.LocalItem; 20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpec; 21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecList; 22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecSet; 23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SourcePosition; 24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Constant; 25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstMemberRef; 26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType; 27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8; 28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type; 29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList; 31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.HashSet; 32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/** 34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Processor for instruction lists, which takes a "first cut" of 35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction selection as a basis and produces a "final cut" in the 36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * form of a {@link DalvInsnList} instance. 37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class OutputFinisher { 39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code >= 0;} register count for the method, not including any extra 41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * "reserved" registers needed to translate "difficult" instructions 42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final int unreservedRegCount; 44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} the list of instructions, per se */ 46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private ArrayList<DalvInsn> insns; 47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** whether any instruction has position info */ 49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private boolean hasAnyPositionInfo; 50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** whether any instruction has local variable info */ 52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private boolean hasAnyLocalInfo; 53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code >= 0;} the count of reserved registers (low-numbered 56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * registers used when expanding instructions that can't be 57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * represented simply); becomes valid after a call to {@link 58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * #massageInstructions} 59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private int reservedCount; 61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Constructs an instance. It initially contains no instructions. 64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param regCount {@code >= 0;} register count for the method 66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param initialCapacity {@code >= 0;} initial capacity of the instructions 67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * list 68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public OutputFinisher(int initialCapacity, int regCount) { 70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.unreservedRegCount = regCount; 71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.insns = new ArrayList<DalvInsn>(initialCapacity); 72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.reservedCount = -1; 73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.hasAnyPositionInfo = false; 74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.hasAnyLocalInfo = false; 75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Returns whether any of the instructions added to this instance 79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * come with position info. 80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return whether any of the instructions added to this instance 82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * come with position info 83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public boolean hasAnyPositionInfo() { 85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return hasAnyPositionInfo; 86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Returns whether this instance has any local variable information. 90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return whether this instance has any local variable information 92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public boolean hasAnyLocalInfo() { 94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return hasAnyLocalInfo; 95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #add} which scrutinizes a single 99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction for local variable information. 100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} instruction to scrutinize 102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code true} iff the instruction refers to any 103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * named locals 104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static boolean hasLocalInfo(DalvInsn insn) { 106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (insn instanceof LocalSnapshot) { 107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); 108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = specs.size(); 109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (hasLocalInfo(specs.get(i))) { 111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return true; 112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else if (insn instanceof LocalStart) { 115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpec spec = ((LocalStart) insn).getLocal(); 116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (hasLocalInfo(spec)) { 117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return true; 118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return false; 122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single 126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * register spec. 127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param spec {@code non-null;} spec to scrutinize 129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code true} iff the spec refers to any 130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * named locals 131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static boolean hasLocalInfo(RegisterSpec spec) { 133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return (spec != null) 134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul && (spec.getLocalItem().getName() != null); 135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Returns the set of all constants referred to by instructions added 139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * to this instance. 140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the set of constants 142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public HashSet<Constant> getAllConstants() { 144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul HashSet<Constant> result = new HashSet<Constant>(20); 145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (DalvInsn insn : insns) { 147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul addConstants(result, insn); 148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #getAllConstants} which adds all the info for 155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * a single instruction. 156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param result {@code non-null;} result set to add to 158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} instruction to scrutinize 159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static void addConstants(HashSet<Constant> result, 161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn) { 162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (insn instanceof CstInsn) { 163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Constant cst = ((CstInsn) insn).getConstant(); 164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(cst); 165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else if (insn instanceof LocalSnapshot) { 166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); 167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = specs.size(); 168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul addConstants(result, specs.get(i)); 170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else if (insn instanceof LocalStart) { 172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpec spec = ((LocalStart) insn).getLocal(); 173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul addConstants(result, spec); 174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #getAllConstants} which adds all the info for 179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * a single {@code RegisterSpec}. 180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param result {@code non-null;} result set to add to 182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param spec {@code null-ok;} register spec to add 183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static void addConstants(HashSet<Constant> result, 185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpec spec) { 186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (spec == null) { 187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return; 188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul LocalItem local = spec.getLocalItem(); 191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CstUtf8 name = local.getName(); 192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CstUtf8 signature = local.getSignature(); 193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Type type = spec.getType(); 194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (type != Type.KNOWN_NULL) { 196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(CstType.intern(type)); 197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (name != null) { 200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(name); 201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (signature != null) { 204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(signature); 205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Adds an instruction to the output. 210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} the instruction to add 212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void add(DalvInsn insn) { 214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.add(insn); 215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul updateInfo(insn); 216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Inserts an instruction in the output at the given offset. 220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param at {@code >= 0;} what index to insert at 222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} the instruction to insert 223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void insert(int at, DalvInsn insn) { 225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.add(at, insn); 226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul updateInfo(insn); 227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #add} and {@link #insert}, 231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * which updates the position and local info flags. 232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} an instruction that was just introduced 234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private void updateInfo(DalvInsn insn) { 236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (! hasAnyPositionInfo) { 237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul SourcePosition pos = insn.getPosition(); 238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (pos.getLine() >= 0) { 239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul hasAnyPositionInfo = true; 240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (! hasAnyLocalInfo) { 244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (hasLocalInfo(insn)) { 245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul hasAnyLocalInfo = true; 246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Reverses a branch which is buried a given number of instructions 252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * backward in the output. It is illegal to call this unless the 253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * indicated instruction really is a reversible branch. 254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param which how many instructions back to find the branch; 256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code 0} is the most recently added instruction, 257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code 1} is the instruction before that, etc. 258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param newTarget {@code non-null;} the new target for the reversed branch 259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void reverseBranch(int which, CodeAddress newTarget) { 261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int index = size - which - 1; 263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul TargetInsn targetInsn; 264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul try { 266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul targetInsn = (TargetInsn) insns.get(index); 267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (IndexOutOfBoundsException ex) { 268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // Translate the exception. 269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalArgumentException("too few instructions"); 270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (ClassCastException ex) { 271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // Translate the exception. 272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalArgumentException("non-reversible instruction"); 273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * No need to call this.set(), since the format and other info 277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * are the same. 278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.set(index, targetInsn.withNewTargetAndReversed(newTarget)); 280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Assigns indices in all instructions that need them, using the 284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * given callback to perform lookups. This should be called before 285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * calling {@link #finishProcessingAndGetList}. 286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param callback {@code non-null;} callback object 288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void assignIndices(DalvCode.AssignIndicesCallback callback) { 290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (DalvInsn insn : insns) { 291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (insn instanceof CstInsn) { 292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul assignIndices((CstInsn) insn, callback); 293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #assignIndices} which does assignment for one 299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction. 300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} the instruction 302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param callback {@code non-null;} the callback 303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static void assignIndices(CstInsn insn, 305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvCode.AssignIndicesCallback callback) { 306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Constant cst = insn.getConstant(); 307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int index = callback.getIndex(cst); 308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (index >= 0) { 310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn.setIndex(index); 311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (cst instanceof CstMemberRef) { 314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CstMemberRef member = (CstMemberRef) cst; 315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CstType definer = member.getDefiningClass(); 316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul index = callback.getIndex(definer); 317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (index >= 0) { 318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn.setClassIndex(index); 319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Does final processing on this instance and gets the output as 325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * a {@link DalvInsnList}. Final processing consists of: 326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <ul> 328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li>optionally renumbering registers (to make room as needed for 329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * expanded instructions)</li> 330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li>picking a final opcode for each instruction</li> 331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li>rewriting instructions, because of register number, 332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * constant pool index, or branch target size issues</li> 333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li>assigning final addresses</li> 334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * </ul> 335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <p><b>Note:</b> This method may only be called once per instance 337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * of this class.</p> 338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the output list 340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @throws UnsupportedOperationException if this method has 341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * already been called 342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public DalvInsnList finishProcessingAndGetList() { 344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (reservedCount >= 0) { 345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new UnsupportedOperationException("already processed"); 346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat[] formats = makeFormatsArray(); 349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul reserveRegisters(formats); 350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul massageInstructions(formats); 351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul assignAddressesAndFixBranches(); 352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return DalvInsnList.makeImmutable(insns, 354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul reservedCount + unreservedRegCount); 355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #finishProcessingAndGetList}, which extracts 359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * the format out of each instruction into a separate array, to be 360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * further manipulated as things progress. 361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the array of formats 363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private InsnFormat[] makeFormatsArray() { 365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat[] result = new InsnFormat[size]; 367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result[i] = insns.get(i).getOpcode().getFormat(); 370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #finishProcessingAndGetList}, which figures 377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * out how many reserved registers are required and then reserving 378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * them. It also updates the given {@code formats} array so 379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * as to avoid extra work when constructing the massaged 380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction list. 381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param formats {@code non-null;} array of per-instruction format selections 383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private void reserveRegisters(InsnFormat[] formats) { 385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount; 386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Call calculateReservedCount() and then perform register 389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * reservation, repeatedly until no new reservations happen. 390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (;;) { 392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int newReservedCount = calculateReservedCount(formats); 393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (oldReservedCount >= newReservedCount) { 394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int reservedDifference = newReservedCount - oldReservedCount; 398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * CodeAddress instance identity is used to link 403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * TargetInsns to their targets, so it is 404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * inappropriate to make replacements, and they don't 405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * have registers in any case. Hence, the instanceof 406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * test below. 407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (!(insn instanceof CodeAddress)) { 410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * No need to call this.set() since the format and 412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * other info are the same. 413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.set(i, insn.withRegisterOffset(reservedDifference)); 415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul oldReservedCount = newReservedCount; 419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul reservedCount = oldReservedCount; 422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #reserveRegisters}, which does one 426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * pass over the instructions, calculating the number of 427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * registers that need to be reserved. It also updates the 428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code formats} list to help avoid extra work in future 429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * register reservation passes. 430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param formats {@code non-null;} array of per-instruction format selections 432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code >= 0;} the count of reserved registers 433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private int calculateReservedCount(InsnFormat[] formats) { 435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Potential new value of reservedCount, which gets updated in the 439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * following loop. It starts out with the existing reservedCount 440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * and gets increased if it turns out that additional registers 441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * need to be reserved. 442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int newReservedCount = reservedCount; 444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat originalFormat = formats[i]; 448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat newFormat = findFormatForInsn(insn, originalFormat); 449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (originalFormat == newFormat) { 451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul continue; 452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (newFormat == null) { 455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * The instruction will need to be expanded, so reserve 457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * registers for it. 458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int reserve = insn.getMinimumRegisterRequirement(); 460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (reserve > newReservedCount) { 461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul newReservedCount = reserve; 462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul formats[i] = newFormat; 466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return newReservedCount; 469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Attempts to fit the given instruction into a format, returning 473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * either a format that the instruction fits into or {@code null} 474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * to indicate that the instruction will need to be expanded. This 475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * fitting process starts with the given format as a first "best 476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * guess" and then pessimizes from there if necessary. 477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param insn {@code non-null;} the instruction in question 479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param format {@code null-ok;} the current guess as to the best instruction 480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * format to use; {@code null} means that no simple format fits 481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code null-ok;} a possibly-different format, which is either a 482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * good fit or {@code null} to indicate that no simple format 483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * fits 484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private InsnFormat findFormatForInsn(DalvInsn insn, InsnFormat format) { 486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (format == null) { 487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // The instruction is already known not to fit any simple format. 488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return format; 489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (format.isCompatible(insn)) { 492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // The instruction already fits in the current best-known format. 493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return format; 494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Dop dop = insn.getOpcode(); 497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int family = dop.getFamily(); 498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (;;) { 500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul format = format.nextUp(); 501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if ((format == null) || 502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul (format.isCompatible(insn) && 503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul (Dops.getOrNull(family, format) != null))) { 504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return format; 509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #finishProcessingAndGetList}, which goes 513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * through each instruction in the output, making sure its opcode 514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * can accomodate its arguments. In cases where the opcode is 515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * unable to do so, this replaces the instruction with a larger 516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction with identical semantics that <i>will</i> work. 517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <p>This method may also reserve a number of low-numbered 519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * registers, renumbering the instructions' original registers, in 520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * order to have register space available in which to move 521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * very-high registers when expanding instructions into 522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * multi-instruction sequences. This expansion is done when no 523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * simple instruction format can be found for a given instruction that 524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * is able to accomodate that instruction's registers.</p> 525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <p>This method ignores issues of branch target size, since 527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * final addresses aren't known at the point that this method is 528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * called.</p> 529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param formats {@code non-null;} array of per-instruction format selections 531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private void massageInstructions(InsnFormat[] formats) { 533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (reservedCount == 0) { 534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * The easy common case: No registers were reserved, so we 536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * merely need to replace any instructions whose format changed 537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * during the reservation pass, but all instructions will stay 538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * at their original indices, and the instruction list doesn't 539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * grow. 540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Dop dop = insn.getOpcode(); 546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat format = formats[i]; 547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (format != dop.getFormat()) { 549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul dop = Dops.getOrNull(dop.getFamily(), format); 550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.set(i, insn.withOpcode(dop)); 551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else { 554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * The difficult uncommon case: Some instructions have to be 556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * expanded to deal with high registers. 557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns = performExpansion(formats); 559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #massageInstructions}, which constructs a 564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * replacement list, where each {link DalvInsn} instance that 565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * couldn't be represented simply (due to register representation 566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * problems) is expanded into a series of instances that together 567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * perform the proper function. 568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param formats {@code non-null;} array of per-instruction format selections 570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the replacement list 571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) { 573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2); 575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Dop dop = insn.getOpcode(); 579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat originalFormat = dop.getFormat(); 580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat currentFormat = formats[i]; 581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn prefix; 582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn suffix; 583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (currentFormat != null) { 585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // No expansion is necessary. 586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul prefix = null; 587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul suffix = null; 588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else { 589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // Expansion is required. 590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul prefix = insn.hrPrefix(); 591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul suffix = insn.hrSuffix(); 592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Get the initial guess as to the hr version, but then 595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * let findFormatForInsn() pick a better format, if any. 596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn = insn.hrVersion(); 598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul originalFormat = insn.getOpcode().getFormat(); 599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul currentFormat = findFormatForInsn(insn, originalFormat); 600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (prefix != null) { 603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(prefix); 604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (currentFormat != originalFormat) { 607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul dop = Dops.getOrNull(dop.getFamily(), currentFormat); 608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn = insn.withOpcode(dop); 609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(insn); 611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (suffix != null) { 613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul result.add(suffix); 614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return result; 618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #finishProcessingAndGetList}, which assigns 622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * addresses to each instruction, possibly rewriting branches to 623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * fix ones that wouldn't otherwise be able to reach their 624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * targets. 625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private void assignAddressesAndFixBranches() { 627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (;;) { 628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul assignAddresses(); 629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (!fixBranches()) { 630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #assignAddressesAndFixBranches}, which 637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * assigns an address to each instruction, in order. 638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private void assignAddresses() { 640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int address = 0; 641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn.setAddress(address); 646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul address += insn.codeSize(); 647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Helper for {@link #assignAddressesAndFixBranches}, which checks 652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * the branch target size requirement of each branch instruction 653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * to make sure it fits. For instructions that don't fit, this 654917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * rewrites them to use a {@code goto} of some sort. In the 655917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * case of a conditional branch that doesn't fit, the sense of the 656917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * test is reversed in order to branch around a {@code goto} 657917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * to the original target. 658917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 659917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return whether any branches had to be fixed 660917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 661917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private boolean fixBranches() { 662917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int size = insns.size(); 663917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul boolean anyFixed = false; 664917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 665917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < size; i++) { 666917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DalvInsn insn = insns.get(i); 667917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (!(insn instanceof TargetInsn)) { 668917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // This loop only needs to inspect TargetInsns. 669917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul continue; 670917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 671917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 672917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Dop dop = insn.getOpcode(); 673917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat format = dop.getFormat(); 674917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul TargetInsn target = (TargetInsn) insn; 675917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 676917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (format.branchFits(target)) { 677917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul continue; 678917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 679917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 680917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (dop.getFamily() == DalvOps.GOTO) { 681917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // It is a goto; widen it if possible. 682917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul InsnFormat newFormat = findFormatForInsn(insn, format); 683917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (newFormat == null) { 684917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 685917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * The branch is already maximally large. This should 686917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * only be possible if a method somehow manages to have 687917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * more than 2^31 code units. 688917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 689917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new UnsupportedOperationException("method too long"); 690917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 691917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul dop = Dops.getOrNull(dop.getFamily(), newFormat); 692917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insn = insn.withOpcode(dop); 693917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.set(i, insn); 694917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else { 695917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 696917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * It is a conditional: Reverse its sense, and arrange for 697917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * it to branch around an absolute goto to the original 698917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * branch target. 699917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 700917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Note: An invariant of the list being processed is 701917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * that every TargetInsn is followed by a CodeAddress. 702917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Hence, it is always safe to get the next element 703917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * after a TargetInsn and cast it to CodeAddress, as 704917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * is happening a few lines down. 705917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 706917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Also note: Size gets incremented by one here, as we 707917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * have -- in the net -- added one additional element 708917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * to the list, so we increment i to match. The added 709917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * and changed elements will be inspected by a repeat 710917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * call to this method after this invocation returns. 711917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 712917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul CodeAddress newTarget; 713917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul try { 714917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul newTarget = (CodeAddress) insns.get(i + 1); 715917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (IndexOutOfBoundsException ex) { 716917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // The TargetInsn / CodeAddress invariant was violated. 717917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalStateException( 718917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul "unpaired TargetInsn (dangling)"); 719917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (ClassCastException ex) { 720917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // The TargetInsn / CodeAddress invariant was violated. 721917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalStateException("unpaired TargetInsn"); 722917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 723917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul TargetInsn gotoInsn = 724917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul new TargetInsn(Dops.GOTO, target.getPosition(), 725917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul RegisterSpecList.EMPTY, target.getTarget()); 726917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.set(i, gotoInsn); 727917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul insns.add(i, target.withNewTargetAndReversed(newTarget)); 728917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul size++; 729917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul i++; 730917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 731917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 732917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul anyFixed = true; 733917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 734917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 735917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return anyFixed; 736917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 737917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul} 738