misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / codegen / Label.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.codegen;
12
13 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
14 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
15
16 /**
17  * This type is a port of smalltalks JavaLabel
18  */
19 public class Label {
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;
26 public Label() {
27 }
28 /**
29  * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
30  */
31 public Label(CodeStream codeStream) {
32         this.codeStream = codeStream;
33 }
34 /**
35  * Add a forward refrence for the array.
36  */
37 void addForwardReference(int iPos) {
38         int length;
39         if (forwardReferenceCount >= (length = forwardReferences.length))
40                 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length);
41         forwardReferences[forwardReferenceCount++] = iPos;
42 }
43 /**
44  * Add a forward refrence for the array.
45  */
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);
53         }
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;
57 }
58 /*
59 * Put down  a refernece to the array at the location in the codestream.
60 */
61 void branch() {
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));
69         }
70 }
71 /*
72 * No support for wide branches yet
73 */
74 void branchWide() {
75         if (position == POS_NOT_SET) {
76                 addForwardReference(codeStream.position);
77                 // Leave 4 bytes free to generate the jump offset afterwards
78                 isWide = true;
79                 codeStream.position += 4;
80                 codeStream.classFileOffset += 4;
81         } else { //Position is set. Write it!
82                 codeStream.writeSignedWord(position - codeStream.position + 1);
83         }
84 }
85 /**
86  * @return boolean
87  */
88 public boolean hasForwardReferences() {
89         return forwardReferenceCount != 0;
90 }
91 /*
92  * Some placed labels might be branching to a goto bytecode which we can optimize better.
93  */
94 public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) {
95 /*
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()){
102                                 return true;
103                         }
104                 }
105                 return false;
106         }
107  */
108         
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);
114                         /*
115                          Code required to optimized unreachable gotos.
116                                 label.position = POS_NOT_SET;
117                         */
118                 } else {
119                         break; // same target labels should be contiguous
120                 }
121         }
122 }
123 public boolean isStandardLabel(){
124         return true;
125 }
126 /*
127 * Place the label. If we have forward references resolve them.
128 */
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
142                                 /** OLD CODE
143                                         int index = codeStream.pcToSourceMapSize - 1;
144                                                 while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) {
145                                                         codeStream.pcToSourceMap[index--][1] = position;
146                                                 }
147                                 */
148                                 // Beginning of new code
149                                 int index = codeStream.pcToSourceMapSize - 2;
150                                 if (codeStream.lastEntryPC == oldPosition) {
151                                         codeStream.lastEntryPC = position;
152                                 }
153                                 if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
154                                         codeStream.pcToSourceMapSize-=2;
155                                 }
156                                 // end of new code
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;
166                                                         }
167                                                         if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
168                                                                 local.initializationPCs[(local.initializationCount - 1) << 1] = position;
169                                                         }
170                                                 }
171                                         }
172                                 }
173                         }
174                 }
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);
179                         }
180                         if (this.codeStream.wideMode) {
181                                 if (this.isWide) {
182                                         codeStream.writeSignedWord(forwardReferences[i], offset);
183                                 } else {
184                                         codeStream.writeSignedShort(forwardReferences[i], (short) offset);
185                                 }
186                         } else {
187                                 codeStream.writeSignedShort(forwardReferences[i], (short) offset);
188                         }
189                 }
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);
203                                                 }
204                                         } else {
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);
210                                                         }
211                                                         if (this.codeStream.wideMode) {
212                                                                 if (this.isWide) {
213                                                                         codeStream.writeSignedWord(forwardPosition, offset);
214                                                                 } else {
215                                                                         codeStream.writeSignedShort(forwardPosition, (short) offset);
216                                                                 }
217                                                         } else {
218                                                                 codeStream.writeSignedShort(forwardPosition, (short) offset);
219                                                         }
220                                                 }
221                                         }
222                                 }
223                         }
224                 }
225         }
226 }
227 /**
228  * Print out the receiver
229  */
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();
240 }
241
242 public void resetStateForCodeGeneration() {
243         this.position = POS_NOT_SET;
244         this.forwardReferenceCount = 0;
245 }
246 }