/******************************************************************************* * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.codegen; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.problem.AbortMethod; /** * 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() { // for creating labels ahead of code generation } /** * @param codeStream org.eclipse.jdt.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 reference 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, null); } codeStream.writeSignedShort(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 void initialize(CodeStream stream) { this.codeStream = stream; this.position = POS_NOT_SET; this.forwardReferenceCount = 0; } public boolean isStandardLabel(){ return true; } /* * Place the label. If we have forward references resolve them. */ public void place() { // Currently lacking wide support. if (CodeStream.DEBUG) System.out.println("\t\t\t\t<place at: "+codeStream.position+" - "+ this); //$NON-NLS-1$ //$NON-NLS-2$ if (position == POS_NOT_SET) { position = codeStream.position; codeStream.addLabel(this); int oldPosition = position; boolean isOptimizedBranch = false; // TURNED OFF since fail on 1F4IRD9 if (forwardReferenceCount != 0) { isOptimizedBranch = (forwardReferences[forwardReferenceCount - 1] + 2 == position) && (codeStream.bCodeStream[codeStream.classFileOffset - 3] == Opcodes.OPC_goto); if (isOptimizedBranch) { 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, null); } if (this.codeStream.wideMode) { if (this.isWide) { codeStream.writeSignedWord(forwardReferences[i], offset); } else { codeStream.writeSignedShort(forwardReferences[i], offset); } } else { codeStream.writeSignedShort(forwardReferences[i], 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 (isOptimizedBranch) { 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, null); } if (this.codeStream.wideMode) { if (this.isWide) { codeStream.writeSignedWord(forwardPosition, offset); } else { codeStream.writeSignedShort(forwardPosition, offset); } } else { codeStream.writeSignedShort(forwardPosition, offset); } } } } } } } } /** * Print out the receiver */ 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(position); //$NON-NLS-1$ 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(); } }