/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler.codegen;

/**
 * This type is a port of smalltalks JavaLabel
 */
public class Label {
	// public CodeStream codeStream;
	final static int POS_NOT_SET = -1;

	public int position = POS_NOT_SET; // position=POS_NOT_SET Then it's pos is
										// not set.

	public int[] forwardReferences = new int[10]; // Add an overflow check
													// here.

	public int forwardReferenceCount = 0;

	//private boolean isWide = false;

	public Label() {
	}

	/**
	 * @param codeStream
	 *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
	 */
	// public Label(CodeStream codeStream) {
	// this.codeStream = codeStream;
	// }
	/**
	 * Add a forward refrence for the array.
	 */
//	void addForwardReference(int iPos) {
//		int length;
//		if (forwardReferenceCount >= (length = forwardReferences.length))
//			System.arraycopy(forwardReferences, 0,
//					(forwardReferences = new int[2 * length]), 0, length);
//		forwardReferences[forwardReferenceCount++] = iPos;
//	}

	/**
	 * Add a forward refrence for the array.
	 */
	public void appendForwardReferencesFrom(Label otherLabel) {
		int otherCount = otherLabel.forwardReferenceCount;
		if (otherCount == 0)
			return;
		int length = forwardReferences.length;
		int neededSpace = otherCount + forwardReferenceCount;
		if (neededSpace >= length) {
			System.arraycopy(forwardReferences, 0,
					(forwardReferences = new int[neededSpace]), 0,
					forwardReferenceCount);
		}
		// append other forward references at the end, so they will get updated
		// as well
		System.arraycopy(otherLabel.forwardReferences, 0, forwardReferences,
				forwardReferenceCount, otherCount);
		forwardReferenceCount = neededSpace;
	}

	/*
	 * Put down a refernece to the array at the location in the codestream.
	 */
	// void branch() {
	// if (position == POS_NOT_SET) {
	// addForwardReference(codeStream.position);
	// // Leave two bytes free to generate the jump afterwards
	// codeStream.position += 2;
	// codeStream.classFileOffset += 2;
	// } else {
	// /*
	// * Position is set. Write it if it is not a wide branch.
	// */
	// int offset = position - codeStream.position + 1;
	// if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
	// throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE);
	// }
	// codeStream.writeSignedShort((short) offset);
	// }
	// }
	/*
	 * No support for wide branches yet
	 */
	// void branchWide() {
	// if (position == POS_NOT_SET) {
	// addForwardReference(codeStream.position);
	// // Leave 4 bytes free to generate the jump offset afterwards
	// isWide = true;
	// codeStream.position += 4;
	// codeStream.classFileOffset += 4;
	// } else { //Position is set. Write it!
	// codeStream.writeSignedWord(position - codeStream.position + 1);
	// }
	// }
	/**
	 * @return boolean
	 */
	public boolean hasForwardReferences() {
		return forwardReferenceCount != 0;
	}

	/*
	 * Some placed labels might be branching to a goto bytecode which we can
	 * optimize better.
	 */
	// public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation)
	// {
	// /*
	// Code required to optimized unreachable gotos.
	// public boolean isBranchTarget(int location) {
	// Label[] labels = codeStream.labels;
	// for (int i = codeStream.countLabels - 1; i >= 0; i--){
	// Label label = labels[i];
	// if ((label.position == location) && label.isStandardLabel()){
	// return true;
	// }
	// }
	// return false;
	// }
	// */
	//	
	// Label[] labels = codeStream.labels;
	// for (int i = codeStream.countLabels - 1; i >= 0; i--){
	// Label label = labels[i];
	// if ((label.position == gotoLocation) && label.isStandardLabel()){
	// this.appendForwardReferencesFrom(label);
	// /*
	// Code required to optimized unreachable gotos.
	// label.position = POS_NOT_SET;
	// */
	// } else {
	// break; // same target labels should be contiguous
	// }
	// }
	// }
//	public boolean isStandardLabel() {
//		return true;
//	}

	/*
	 * Place the label. If we have forward references resolve them.
	 */
	// public void place() { // Currently lacking wide support.
	// if (position == POS_NOT_SET) {
	// position = codeStream.position;
	// codeStream.addLabel(this);
	// int oldPosition = position;
	// boolean optimizedBranch = false;
	// // TURNED OFF since fail on 1F4IRD9
	// if (forwardReferenceCount != 0) {
	// if (optimizedBranch = (forwardReferences[forwardReferenceCount - 1] + 2
	// == position) && (codeStream.bCodeStream[codeStream.classFileOffset - 3]
	// == CodeStream.OPC_goto)) {
	// codeStream.position = (position -= 3);
	// codeStream.classFileOffset -= 3;
	// forwardReferenceCount--;
	// // also update the PCs in the related debug attributes
	// /** OLD CODE
	// int index = codeStream.pcToSourceMapSize - 1;
	// while ((index >= 0) && (codeStream.pcToSourceMap[index][1] ==
	// oldPosition)) {
	// codeStream.pcToSourceMap[index--][1] = position;
	// }
	// */
	// // Beginning of new code
	// int index = codeStream.pcToSourceMapSize - 2;
	// if (codeStream.lastEntryPC == oldPosition) {
	// codeStream.lastEntryPC = position;
	// }
	// if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
	// codeStream.pcToSourceMapSize-=2;
	// }
	// // end of new code
	// if (codeStream.generateLocalVariableTableAttributes) {
	// LocalVariableBinding locals[] = 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] =
	// position;
	// }
	// if (local.initializationPCs[(local.initializationCount - 1) << 1] ==
	// oldPosition) {
	// local.initializationPCs[(local.initializationCount - 1) << 1] = position;
	// }
	// }
	// }
	// }
	// }
	// }
	// for (int i = 0; i < forwardReferenceCount; i++) {
	// int offset = position - forwardReferences[i] + 1;
	// if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
	// throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE);
	// }
	// if (this.codeStream.wideMode) {
	// if (this.isWide) {
	// codeStream.writeSignedWord(forwardReferences[i], offset);
	// } else {
	// codeStream.writeSignedShort(forwardReferences[i], (short) offset);
	// }
	// } else {
	// codeStream.writeSignedShort(forwardReferences[i], (short) offset);
	// }
	// }
	// // 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 (optimizedBranch) {
	// for (int i = 0; i < codeStream.countLabels; i++) {
	// Label label = codeStream.labels[i];
	// if (oldPosition == label.position) {
	// label.position = position;
	// if (label instanceof CaseLabel) {
	// int offset = position - ((CaseLabel) label).instructionPosition;
	// for (int j = 0; j < label.forwardReferenceCount; j++) {
	// int forwardPosition = label.forwardReferences[j];
	// codeStream.writeSignedWord(forwardPosition, offset);
	// }
	// } else {
	// for (int j = 0; j < label.forwardReferenceCount; j++) {
	// int forwardPosition = label.forwardReferences[j];
	// int offset = position - forwardPosition + 1;
	// if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
	// throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE);
	// }
	// if (this.codeStream.wideMode) {
	// if (this.isWide) {
	// codeStream.writeSignedWord(forwardPosition, offset);
	// } else {
	// codeStream.writeSignedShort(forwardPosition, (short) offset);
	// }
	// } else {
	// codeStream.writeSignedShort(forwardPosition, (short) offset);
	// }
	// }
	// }
	// }
	// }
	// }
	// }
	// }
	/**
	 * Print out the receiver
	 */
	public String toString() {
		StringBuffer buffer = new StringBuffer("(position="); //$NON-NLS-1$
		buffer.append(position);
		buffer.append(", forwards = ["); //$NON-NLS-1$
		for (int i = 0; i < forwardReferenceCount - 1; i++)
			buffer.append(forwardReferences[i] + ", "); //$NON-NLS-1$
		if (forwardReferenceCount >= 1)
			buffer.append(forwardReferences[forwardReferenceCount - 1]);
		buffer.append("] )"); //$NON-NLS-1$
		return buffer.toString();
	}

	public void resetStateForCodeGeneration() {
		this.position = POS_NOT_SET;
		this.forwardReferenceCount = 0;
	}
}