package org.eclipse.jdt.internal.compiler.codegen;
import java.util.Arrays;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
public class BranchLabel extends Label {
private int[] forwardReferences = new int[10];
private int forwardReferenceCount = 0;
BranchLabel delegate;
public int tagBits;
public final static int WIDE = 1;
public final static int USED = 2;
public BranchLabel() {
}
public BranchLabel(CodeStream codeStream) {
super(codeStream);
}
void addForwardReference(int pos) {
if (this.delegate != null) {
this.delegate.addForwardReference(pos);
return;
}
final int count = this.forwardReferenceCount;
if (count >= 1) {
int previousValue = this.forwardReferences[count - 1];
if (previousValue < pos) {
int length;
if (count >= (length = this.forwardReferences.length))
System.arraycopy(this.forwardReferences, 0, (this.forwardReferences = new int[2*length]), 0, length);
this.forwardReferences[this.forwardReferenceCount++] = pos;
} else if (previousValue > pos) {
int[] refs = this.forwardReferences;
for (int i = 0, max = this.forwardReferenceCount; i < max; i++) {
if (refs[i] == pos) return;
}
int length;
if (count >= (length = refs.length))
System.arraycopy(refs, 0, (this.forwardReferences = new int[2*length]), 0, length);
this.forwardReferences[this.forwardReferenceCount++] = pos;
Arrays.sort(this.forwardReferences, 0, this.forwardReferenceCount);
}
} else {
int length;
if (count >= (length = this.forwardReferences.length))
System.arraycopy(this.forwardReferences, 0, (this.forwardReferences = new int[2*length]), 0, length);
this.forwardReferences[this.forwardReferenceCount++] = pos;
}
}
public void becomeDelegateFor(BranchLabel otherLabel) {
otherLabel.delegate = this;
final int otherCount = otherLabel.forwardReferenceCount;
if (otherCount == 0) return;
int[] mergedForwardReferences = new int[this.forwardReferenceCount + otherCount];
int indexInMerge = 0;
int j = 0;
int i = 0;
int max = this.forwardReferenceCount;
int max2 = otherLabel.forwardReferenceCount;
loop1 : for (; i < max; i++) {
final int value1 = this.forwardReferences[i];
for (; j < max2; j++) {
final int value2 = otherLabel.forwardReferences[j];
if (value1 < value2) {
mergedForwardReferences[indexInMerge++] = value1;
continue loop1;
} else if (value1 == value2) {
mergedForwardReferences[indexInMerge++] = value1;
j++;
continue loop1;
} else {
mergedForwardReferences[indexInMerge++] = value2;
}
}
mergedForwardReferences[indexInMerge++] = value1;
}
for (; j < max2; j++) {
mergedForwardReferences[indexInMerge++] = otherLabel.forwardReferences[j];
}
this.forwardReferences = mergedForwardReferences;
this.forwardReferenceCount = indexInMerge;
}
void branch() {
this.tagBits |= BranchLabel.USED;
if (this.delegate != null) {
this.delegate.branch();
return;
}
if (this.position == Label.POS_NOT_SET) {
addForwardReference(this.codeStream.position);
this.codeStream.position += 2;
this.codeStream.classFileOffset += 2;
} else {
this.codeStream.writePosition(this);
}
}
void branchWide() {
this.tagBits |= BranchLabel.USED;
if (this.delegate != null) {
this.delegate.branchWide();
return;
}
if (this.position == Label.POS_NOT_SET) {
addForwardReference(this.codeStream.position);
this.tagBits |= BranchLabel.WIDE;
this.codeStream.position += 4;
this.codeStream.classFileOffset += 4;
} else {
this.codeStream.writeWidePosition(this);
}
}
public int forwardReferenceCount() {
if (this.delegate != null) this.delegate.forwardReferenceCount();
return this.forwardReferenceCount;
}
public int[] forwardReferences() {
if (this.delegate != null) this.delegate.forwardReferences();
return this.forwardReferences;
}
public void initialize(CodeStream stream) {
this.codeStream = stream;
this.position = Label.POS_NOT_SET;
this.forwardReferenceCount = 0;
this.delegate = null;
}
public boolean isCaseLabel() {
return false;
}
public boolean isStandardLabel(){
return true;
}
@Override
public void place() {
if (this.position == Label.POS_NOT_SET) {
this.position = this.codeStream.position;
this.codeStream.addLabel(this);
int oldPosition = this.position;
boolean isOptimizedBranch = false;
if (this.forwardReferenceCount != 0) {
isOptimizedBranch = (this.forwardReferences[this.forwardReferenceCount - 1] + 2 == this.position) && (this.codeStream.bCodeStream[this.codeStream.classFileOffset - 3] == Opcodes.OPC_goto);
if (isOptimizedBranch) {
if (this.codeStream.lastAbruptCompletion == this.position) {
this.codeStream.lastAbruptCompletion = -1;
}
this.codeStream.position = (this.position -= 3);
this.codeStream.classFileOffset -= 3;
this.forwardReferenceCount--;
if (this.codeStream.lastEntryPC == oldPosition) {
this.codeStream.lastEntryPC = this.position;
}
if ((this.codeStream.generateAttributes & (ClassFileConstants.ATTR_VARS | ClassFileConstants.ATTR_STACK_MAP_TABLE | ClassFileConstants.ATTR_STACK_MAP)) != 0) {
LocalVariableBinding locals[] = this.codeStream.locals;
for (int i = 0, max = locals.length; i < max; i++) {
LocalVariableBinding local = locals[i];
if ((local != null) && (local.initializationCount > 0)) {
if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) {
local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = this.position;
}
if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
local.initializationPCs[(local.initializationCount - 1) << 1] = this.position;
}
}
}
}
if ((this.codeStream.generateAttributes & ClassFileConstants.ATTR_LINES) != 0) {
this.codeStream.removeUnusedPcToSourceMapEntries();
}
}
}
for (int i = 0; i < this.forwardReferenceCount; i++) {
this.codeStream.writePosition(this, this.forwardReferences[i]);
}
if (isOptimizedBranch) {
this.codeStream.optimizeBranch(oldPosition, this);
}
}
}
@Override
public String toString() {
String basic = getClass().getName();
basic = basic.substring(basic.lastIndexOf('.')+1);
StringBuffer buffer = new StringBuffer(basic);
buffer.append('@').append(Integer.toHexString(hashCode()));
buffer.append("(position=").append(this.position);
if (this.delegate != null) buffer.append("delegate=").append(this.delegate);
buffer.append(", forwards = [");
for (int i = 0; i < this.forwardReferenceCount - 1; i++)
buffer.append(this.forwardReferences[i] + ", ");
if (this.forwardReferenceCount >= 1)
buffer.append(this.forwardReferences[this.forwardReferenceCount-1]);
buffer.append("] )");
return buffer.toString();
}
}