org.eclipse.jdt.internal.compiler.codegen.BranchLabel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
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]; // Add an overflow check here.
private int forwardReferenceCount = 0;
BranchLabel delegate; //
// Label tagbits
public int tagBits;
public final static int WIDE = 1;
public final static int USED = 2;
public BranchLabel() {
// for creating labels ahead of code generation
}
/**
* @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
*/
public BranchLabel(CodeStream codeStream) {
super(codeStream);
}
/**
* Add a forward refrence for the array.
*/
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;
// check for duplicates
for (int i = 0, max = this.forwardReferenceCount; i < max; i++) {
if (refs[i] == pos) return; // already recorded
}
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;
}
}
/**
* Makes the current label inline all references to the other label
*/
public void becomeDelegateFor(BranchLabel otherLabel) {
// other label is delegating to receiver from now on
otherLabel.delegate = this;
// all existing forward refs to other label are inlined into current label
final int otherCount = otherLabel.forwardReferenceCount;
if (otherCount == 0) return;
// need to merge the two sorted arrays of forward references
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;
}
/*
* Put down a reference to the array at the location in the codestream.
*/
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);
// Leave two bytes free to generate the jump afterwards
this.codeStream.position += 2;
this.codeStream.classFileOffset += 2;
} else {
/*
* Position is set. Write it if it is not a wide branch.
*/
this.codeStream.writePosition(this);
}
}
/*
* No support for wide branches yet
*/
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);
// Leave 4 bytes free to generate the jump offset afterwards
this.tagBits |= BranchLabel.WIDE;
this.codeStream.position += 4;
this.codeStream.classFileOffset += 4;
} else { //Position is set. Write it!
this.codeStream.writeWidePosition(this);
}
}
public int forwardReferenceCount() {
if (this.delegate != null) return this.delegate.forwardReferenceCount();
return this.forwardReferenceCount;
}
public int[] forwardReferences() {
if (this.delegate != null) return 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;
}
/*
* Place the label. If we have forward references resolve them.
*/
@Override
public void place() { // Currently lacking wide support.
// if ((this.tagBits & USED) == 0 && this.forwardReferenceCount == 0) {
// return;
// }
//TODO how can position be set already ? cannot place more than once
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;
}
// end of new code
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) {
// we want to prevent interval of size 0 to have a negative size.
// see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute
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) {
// we need to remove all entries that is beyond this.position inside the pcToSourcerMap table
this.codeStream.removeUnusedPcToSourceMapEntries();
}
}
}
for (int i = 0; i < this.forwardReferenceCount; i++) {
this.codeStream.writePosition(this, this.forwardReferences[i]);
}
// For all labels placed at that position we check if we need to rewrite the jump
// offset. It is the case each time a label had a forward reference to the current position.
// Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details.
if (isOptimizedBranch) {
this.codeStream.optimizeBranch(oldPosition, this);
}
}
}
/**
* Print out the receiver
*/
@Override
public String toString() {
String basic = getClass().getName();
basic = basic.substring(basic.lastIndexOf('.')+1);
StringBuilder buffer = new StringBuilder(basic);
buffer.append('@').append(Integer.toHexString(hashCode()));
buffer.append("(position=").append(this.position); //$NON-NLS-1$
if (this.delegate != null) buffer.append("delegate=").append(this.delegate); //$NON-NLS-1$
buffer.append(", forwards = ["); //$NON-NLS-1$
for (int i = 0; i < this.forwardReferenceCount - 1; i++)
buffer.append(this.forwardReferences[i] + ", "); //$NON-NLS-1$
if (this.forwardReferenceCount >= 1)
buffer.append(this.forwardReferences[this.forwardReferenceCount-1]);
buffer.append("] )"); //$NON-NLS-1$
return buffer.toString();
}
}