MethodLocation.java revision e80efa670f1027fdf3882a298216a460199e38d0
1package org.jf.dexlib2.builder; 2 3import com.google.common.collect.Lists; 4import org.jf.dexlib2.builder.debug.*; 5import org.jf.dexlib2.iface.instruction.Instruction; 6import org.jf.dexlib2.iface.reference.StringReference; 7import org.jf.dexlib2.iface.reference.TypeReference; 8import org.jf.dexlib2.writer.builder.BuilderStringReference; 9 10import javax.annotation.Nonnull; 11import javax.annotation.Nullable; 12import java.util.AbstractSet; 13import java.util.Iterator; 14import java.util.List; 15import java.util.Set; 16 17public class MethodLocation { 18 @Nullable BuilderInstruction instruction; 19 int codeAddress; 20 int index; 21 22 private List<Label> labels = Lists.newArrayList(); 23 List<BuilderDebugItem> debugItems = Lists.newArrayList(); 24 25 MethodLocation(@Nullable BuilderInstruction instruction, 26 int codeAddress, int index) { 27 this.instruction = instruction; 28 this.codeAddress = codeAddress; 29 this.index = index; 30 } 31 32 @Nullable 33 public Instruction getInstruction() { 34 return instruction; 35 } 36 37 public int getCodeAddress() { 38 return codeAddress; 39 } 40 41 public int getIndex() { 42 return index; 43 } 44 45 void mergeInto(@Nonnull MethodLocation other) { 46 for (Label label: labels) { 47 label.location = other; 48 other.labels.add(label); 49 } 50 51 // We need to keep the debug items in the same order. We add the other debug items to this list, then reassign 52 // the list. 53 for (BuilderDebugItem debugItem: debugItems) { 54 debugItem.location = other; 55 } 56 debugItems.addAll(other.debugItems); 57 other.debugItems = debugItems; 58 59 for (int i=debugItems.size()-1; i>=0; i--) { 60 BuilderDebugItem debugItem = debugItems.get(i); 61 debugItem.location = other; 62 other.debugItems.add(0, debugItem); 63 } 64 for (BuilderDebugItem debugItem: debugItems) { 65 debugItem.location = other; 66 other.debugItems.add(0, debugItem); 67 } 68 } 69 70 @Nonnull 71 public Set<Label> getLabels() { 72 return new AbstractSet<Label>() { 73 @Nonnull 74 @Override public Iterator<Label> iterator() { 75 final Iterator<Label> it = labels.iterator(); 76 77 return new Iterator<Label>() { 78 private @Nullable Label currentLabel = null; 79 80 @Override public boolean hasNext() { 81 return it.hasNext(); 82 } 83 84 @Override public Label next() { 85 currentLabel = it.next(); 86 return currentLabel; 87 } 88 89 @Override public void remove() { 90 if (currentLabel != null) { 91 currentLabel.location = null; 92 } 93 it.remove(); 94 } 95 }; 96 } 97 98 @Override public int size() { 99 return labels.size(); 100 } 101 102 @Override public boolean add(@Nonnull Label label) { 103 if (label.isPlaced()) { 104 throw new IllegalArgumentException("Cannot add a label that is already placed. You must remove " + 105 "it from its current location first."); 106 } 107 label.location = MethodLocation.this; 108 labels.add(label); 109 return true; 110 } 111 }; 112 } 113 114 @Nonnull 115 public Label addNewLabel() { 116 Label label = new Label(this); 117 labels.add(label); 118 return label; 119 } 120 121 @Nonnull 122 public Set<BuilderDebugItem> getDebugItems() { 123 return new AbstractSet<BuilderDebugItem>() { 124 @Nonnull 125 @Override public Iterator<BuilderDebugItem> iterator() { 126 final Iterator<BuilderDebugItem> it = debugItems.iterator(); 127 128 return new Iterator<BuilderDebugItem>() { 129 private @Nullable BuilderDebugItem currentDebugItem = null; 130 131 @Override public boolean hasNext() { 132 return it.hasNext(); 133 } 134 135 @Override public BuilderDebugItem next() { 136 currentDebugItem = it.next(); 137 return currentDebugItem; 138 } 139 140 @Override public void remove() { 141 if (currentDebugItem != null) { 142 currentDebugItem.location = null; 143 } 144 it.remove(); 145 } 146 }; 147 } 148 149 @Override public int size() { 150 return labels.size(); 151 } 152 153 @Override public boolean add(@Nonnull BuilderDebugItem debugItem) { 154 if (debugItem.location != null) { 155 throw new IllegalArgumentException("Cannot add a debug item that has already been added to a " + 156 "method. You must remove it from its current location first."); 157 } 158 debugItem.location = MethodLocation.this; 159 debugItems.add(debugItem); 160 return true; 161 } 162 }; 163 } 164 165 public void addLineNumber(int lineNumber) { 166 debugItems.add(new BuilderLineNumber(this, lineNumber)); 167 } 168 169 public void addStartLocal(int registerNumber, @Nullable StringReference name, @Nullable TypeReference type, 170 @Nullable StringReference signature) { 171 debugItems.add(new BuilderStartLocal(this, registerNumber, name, type, signature)); 172 } 173 174 public void addEndLocal(int registerNumber) { 175 debugItems.add(new BuilderEndLocal(this, registerNumber)); 176 } 177 178 public void addRestartLocal(int registerNumber) { 179 debugItems.add(new BuilderRestartLocal(this, registerNumber)); 180 } 181 182 public void addPrologue() { 183 debugItems.add(new BuilderPrologueEnd(this)); 184 } 185 186 public void addEpilogue() { 187 debugItems.add(new BuilderEpilogueBegin(this)); 188 } 189 190 public void addSetSourceFile(@Nullable BuilderStringReference sourceFile) { 191 debugItems.add(new BuilderSetSourceFile(this, sourceFile)); 192 } 193} 194