1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.codegen;
13 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
14 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
17 * This type is a port of smalltalks JavaLabel
20 public CodeStream codeStream;
21 final static int POS_NOT_SET = -1;
22 public int position = POS_NOT_SET; // position=POS_NOT_SET Then it's pos is not set.
23 public int[] forwardReferences = new int[10]; // Add an overflow check here.
24 public int forwardReferenceCount = 0;
25 private boolean isWide = false;
29 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
31 public Label(CodeStream codeStream) {
32 this.codeStream = codeStream;
35 * Add a forward refrence for the array.
37 void addForwardReference(int iPos) {
39 if (forwardReferenceCount >= (length = forwardReferences.length))
40 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length);
41 forwardReferences[forwardReferenceCount++] = iPos;
44 * Add a forward refrence for the array.
46 public void appendForwardReferencesFrom(Label otherLabel) {
47 int otherCount = otherLabel.forwardReferenceCount;
48 if (otherCount == 0) return;
49 int length = forwardReferences.length;
50 int neededSpace = otherCount + forwardReferenceCount;
51 if (neededSpace >= length){
52 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[neededSpace]), 0, forwardReferenceCount);
54 // append other forward references at the end, so they will get updated as well
55 System.arraycopy(otherLabel.forwardReferences, 0, forwardReferences, forwardReferenceCount, otherCount);
56 forwardReferenceCount = neededSpace;
59 * Put down a refernece to the array at the location in the codestream.
62 if (position == POS_NOT_SET) {
63 addForwardReference(codeStream.position);
64 // Leave two bytes free to generate the jump afterwards
65 codeStream.position += 2;
66 codeStream.classFileOffset += 2;
67 } else { //Position is set. Write it!
68 codeStream.writeSignedShort((short) (position - codeStream.position + 1));
72 * No support for wide branches yet
75 if (position == POS_NOT_SET) {
76 addForwardReference(codeStream.position);
77 // Leave 4 bytes free to generate the jump offset afterwards
79 codeStream.position += 4;
80 codeStream.classFileOffset += 4;
81 } else { //Position is set. Write it!
82 codeStream.writeSignedWord(position - codeStream.position + 1);
88 public boolean hasForwardReferences() {
89 return forwardReferenceCount != 0;
92 * Some placed labels might be branching to a goto bytecode which we can optimize better.
94 public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) {
96 Code required to optimized unreachable gotos.
97 public boolean isBranchTarget(int location) {
98 Label[] labels = codeStream.labels;
99 for (int i = codeStream.countLabels - 1; i >= 0; i--){
100 Label label = labels[i];
101 if ((label.position == location) && label.isStandardLabel()){
109 Label[] labels = codeStream.labels;
110 for (int i = codeStream.countLabels - 1; i >= 0; i--){
111 Label label = labels[i];
112 if ((label.position == gotoLocation) && label.isStandardLabel()){
113 this.appendForwardReferencesFrom(label);
115 Code required to optimized unreachable gotos.
116 label.position = POS_NOT_SET;
119 break; // same target labels should be contiguous
123 public boolean isStandardLabel(){
127 * Place the label. If we have forward references resolve them.
129 public void place() { // Currently lacking wide support.
130 if (position == POS_NOT_SET) {
131 position = codeStream.position;
132 codeStream.addLabel(this);
133 int oldPosition = position;
134 boolean optimizedBranch = false;
135 // TURNED OFF since fail on 1F4IRD9
136 if (forwardReferenceCount != 0) {
137 if (optimizedBranch = (forwardReferences[forwardReferenceCount - 1] + 2 == position) && (codeStream.bCodeStream[codeStream.classFileOffset - 3] == CodeStream.OPC_goto)) {
138 codeStream.position = (position -= 3);
139 codeStream.classFileOffset -= 3;
140 forwardReferenceCount--;
141 // also update the PCs in the related debug attributes
143 int index = codeStream.pcToSourceMapSize - 1;
144 while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) {
145 codeStream.pcToSourceMap[index--][1] = position;
148 // Beginning of new code
149 int index = codeStream.pcToSourceMapSize - 2;
150 if (codeStream.lastEntryPC == oldPosition) {
151 codeStream.lastEntryPC = position;
153 if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
154 codeStream.pcToSourceMapSize-=2;
157 if (codeStream.generateLocalVariableTableAttributes) {
158 LocalVariableBinding locals[] = codeStream.locals;
159 for (int i = 0, max = locals.length; i < max; i++) {
160 LocalVariableBinding local = locals[i];
161 if ((local != null) && (local.initializationCount > 0)) {
162 if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) {
163 // we want to prevent interval of size 0 to have a negative size.
164 // see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute
165 local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position;
167 if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
168 local.initializationPCs[(local.initializationCount - 1) << 1] = position;
175 for (int i = 0; i < forwardReferenceCount; i++) {
176 int offset = position - forwardReferences[i] + 1;
177 if (offset > 0x7FFF && !this.codeStream.wideMode) {
178 throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE);
180 if (this.codeStream.wideMode) {
182 codeStream.writeSignedWord(forwardReferences[i], offset);
184 codeStream.writeSignedShort(forwardReferences[i], (short) offset);
187 codeStream.writeSignedShort(forwardReferences[i], (short) offset);
190 // For all labels placed at that position we check if we need to rewrite the jump
191 // offset. It is the case each time a label had a forward reference to the current position.
192 // Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details.
193 if (optimizedBranch) {
194 for (int i = 0; i < codeStream.countLabels; i++) {
195 Label label = codeStream.labels[i];
196 if (oldPosition == label.position) {
197 label.position = position;
198 if (label instanceof CaseLabel) {
199 int offset = position - ((CaseLabel) label).instructionPosition;
200 for (int j = 0; j < label.forwardReferenceCount; j++) {
201 int forwardPosition = label.forwardReferences[j];
202 codeStream.writeSignedWord(forwardPosition, offset);
205 for (int j = 0; j < label.forwardReferenceCount; j++) {
206 int forwardPosition = label.forwardReferences[j];
207 int offset = position - forwardPosition + 1;
208 if (offset > 0x7FFF && !this.codeStream.wideMode) {
209 throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE);
211 if (this.codeStream.wideMode) {
213 codeStream.writeSignedWord(forwardPosition, offset);
215 codeStream.writeSignedShort(forwardPosition, (short) offset);
218 codeStream.writeSignedShort(forwardPosition, (short) offset);
228 * Print out the receiver
230 public String toString() {
231 StringBuffer buffer = new StringBuffer("(position="); //$NON-NLS-1$
232 buffer.append(position);
233 buffer.append(", forwards = ["); //$NON-NLS-1$
234 for (int i = 0; i < forwardReferenceCount - 1; i++)
235 buffer.append(forwardReferences[i] + ", "); //$NON-NLS-1$
236 if (forwardReferenceCount >= 1)
237 buffer.append(forwardReferences[forwardReferenceCount-1]);
238 buffer.append("] )"); //$NON-NLS-1$
239 return buffer.toString();
242 public void resetStateForCodeGeneration() {
243 this.position = POS_NOT_SET;
244 this.forwardReferenceCount = 0;