Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / codegen / Label.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.codegen;
12
13 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
14 import org.eclipse.jdt.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         
27 public Label() {
28         // for creating labels ahead of code generation
29 }
30 /**
31  * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
32  */
33 public Label(CodeStream codeStream) {
34         this.codeStream = codeStream;
35 }
36 /**
37  * Add a forward refrence for the array.
38  */
39 void addForwardReference(int iPos) {
40         int length;
41         if (forwardReferenceCount >= (length = forwardReferences.length))
42                 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length);
43         forwardReferences[forwardReferenceCount++] = iPos;
44 }
45 /**
46  * Add a forward refrence for the array.
47  */
48 public void appendForwardReferencesFrom(Label otherLabel) {
49         int otherCount = otherLabel.forwardReferenceCount;
50         if (otherCount == 0) return;
51         int length = forwardReferences.length;
52         int neededSpace = otherCount + forwardReferenceCount;
53         if (neededSpace >= length){
54                 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[neededSpace]), 0, forwardReferenceCount);
55         }
56         // append other forward references at the end, so they will get updated as well
57         System.arraycopy(otherLabel.forwardReferences, 0, forwardReferences, forwardReferenceCount, otherCount);
58         forwardReferenceCount = neededSpace;
59 }
60 /*
61 * Put down  a reference to the array at the location in the codestream.
62 */
63 void branch() {
64         if (position == POS_NOT_SET) {
65                 addForwardReference(codeStream.position);
66                 // Leave two bytes free to generate the jump afterwards
67                 codeStream.position += 2;
68                 codeStream.classFileOffset += 2;
69         } else {
70                 /*
71                  * Position is set. Write it if it is not a wide branch.
72                  */
73                 int offset = position - codeStream.position + 1;
74                 if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
75                         throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null);
76                 }
77                 codeStream.writeSignedShort(offset);
78         }
79 }
80 /*
81 * No support for wide branches yet
82 */
83 void branchWide() {
84         if (position == POS_NOT_SET) {
85                 addForwardReference(codeStream.position);
86                 // Leave 4 bytes free to generate the jump offset afterwards
87                 isWide = true;
88                 codeStream.position += 4;
89                 codeStream.classFileOffset += 4;
90         } else { //Position is set. Write it!
91                 codeStream.writeSignedWord(position - codeStream.position + 1);
92         }
93 }
94 /**
95  * @return boolean
96  */
97 public boolean hasForwardReferences() {
98         return forwardReferenceCount != 0;
99 }
100 /*
101  * Some placed labels might be branching to a goto bytecode which we can optimize better.
102  */
103 public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) {
104         
105 /*
106  Code required to optimized unreachable gotos.
107         public boolean isBranchTarget(int location) {
108                 Label[] labels = codeStream.labels;
109                 for (int i = codeStream.countLabels - 1; i >= 0; i--){
110                         Label label = labels[i];
111                         if ((label.position == location) && label.isStandardLabel()){
112                                 return true;
113                         }
114                 }
115                 return false;
116         }
117  */
118         
119         Label[] labels = codeStream.labels;
120         for (int i = codeStream.countLabels - 1; i >= 0; i--){
121                 Label label = labels[i];
122                 if ((label.position == gotoLocation) && label.isStandardLabel()){
123                         this.appendForwardReferencesFrom(label);
124                         /*
125                          Code required to optimized unreachable gotos.
126                                 label.position = POS_NOT_SET;
127                         */
128                 } else {
129                         break; // same target labels should be contiguous
130                 }
131         }
132 }
133 public void initialize(CodeStream stream) {
134     this.codeStream = stream;
135         this.position = POS_NOT_SET;
136         this.forwardReferenceCount = 0; 
137 }
138 public boolean isStandardLabel(){
139         return true;
140 }
141 /*
142 * Place the label. If we have forward references resolve them.
143 */
144 public void place() { // Currently lacking wide support.
145         if (CodeStream.DEBUG) System.out.println("\t\t\t\t<place at: "+codeStream.position+" - "+ this); //$NON-NLS-1$ //$NON-NLS-2$
146
147         if (position == POS_NOT_SET) {
148                 position = codeStream.position;
149                 codeStream.addLabel(this);
150                 int oldPosition = position;
151                 boolean isOptimizedBranch = false;
152                 // TURNED OFF since fail on 1F4IRD9
153                 if (forwardReferenceCount != 0) {
154                         isOptimizedBranch = (forwardReferences[forwardReferenceCount - 1] + 2 == position) && (codeStream.bCodeStream[codeStream.classFileOffset - 3] == Opcodes.OPC_goto);
155                         if (isOptimizedBranch) {
156                                 codeStream.position = (position -= 3);
157                                 codeStream.classFileOffset -= 3;
158                                 forwardReferenceCount--;
159                                 // also update the PCs in the related debug attributes
160                                 /** OLD CODE
161                                         int index = codeStream.pcToSourceMapSize - 1;
162                                                 while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) {
163                                                         codeStream.pcToSourceMap[index--][1] = position;
164                                                 }
165                                 */
166                                 // Beginning of new code
167                                 int index = codeStream.pcToSourceMapSize - 2;
168                                 if (codeStream.lastEntryPC == oldPosition) {
169                                         codeStream.lastEntryPC = position;
170                                 }
171                                 if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
172                                         codeStream.pcToSourceMapSize-=2;
173                                 }
174                                 // end of new code
175                                 if (codeStream.generateLocalVariableTableAttributes) {
176                                         LocalVariableBinding locals[] = codeStream.locals;
177                                         for (int i = 0, max = locals.length; i < max; i++) {
178                                                 LocalVariableBinding local = locals[i];
179                                                 if ((local != null) && (local.initializationCount > 0)) {
180                                                         if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) {
181                                                                 // we want to prevent interval of size 0 to have a negative size.
182                                                                 // see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute
183                                                                 local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position;
184                                                         }
185                                                         if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
186                                                                 local.initializationPCs[(local.initializationCount - 1) << 1] = position;
187                                                         }
188                                                 }
189                                         }
190                                 }
191                         }
192                 }
193                 for (int i = 0; i < forwardReferenceCount; i++) {
194                         int offset = position - forwardReferences[i] + 1;
195                         if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
196                                 throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null);
197                         }
198                         if (this.codeStream.wideMode) {
199                                 if (this.isWide) {
200                                         codeStream.writeSignedWord(forwardReferences[i], offset);
201                                 } else {
202                                         codeStream.writeSignedShort(forwardReferences[i], offset);
203                                 }
204                         } else {
205                                 codeStream.writeSignedShort(forwardReferences[i], offset);
206                         }
207                 }
208                 // For all labels placed at that position we check if we need to rewrite the jump
209                 // offset. It is the case each time a label had a forward reference to the current position.
210                 // Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details.
211                 if (isOptimizedBranch) {
212                         for (int i = 0; i < codeStream.countLabels; i++) {
213                                 Label label = codeStream.labels[i];
214                                 if (oldPosition == label.position) {
215                                         label.position = position;
216                                         if (label instanceof CaseLabel) {
217                                                 int offset = position - ((CaseLabel) label).instructionPosition;
218                                                 for (int j = 0; j < label.forwardReferenceCount; j++) {
219                                                         int forwardPosition = label.forwardReferences[j];
220                                                         codeStream.writeSignedWord(forwardPosition, offset);
221                                                 }
222                                         } else {
223                                                 for (int j = 0; j < label.forwardReferenceCount; j++) {
224                                                         int forwardPosition = label.forwardReferences[j];
225                                                         int offset = position - forwardPosition + 1;
226                                                         if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) {
227                                                                 throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null);
228                                                         }
229                                                         if (this.codeStream.wideMode) {
230                                                                 if (this.isWide) {
231                                                                         codeStream.writeSignedWord(forwardPosition, offset);
232                                                                 } else {
233                                                                         codeStream.writeSignedShort(forwardPosition, offset);
234                                                                 }
235                                                         } else {
236                                                                 codeStream.writeSignedShort(forwardPosition, offset);
237                                                         }
238                                                 }
239                                         }
240                                 }
241                         }
242                 }
243         }
244 }
245 /**
246  * Print out the receiver
247  */
248 public String toString() {
249         String basic = getClass().getName();
250         basic = basic.substring(basic.lastIndexOf('.')+1);
251         StringBuffer buffer = new StringBuffer(basic); 
252         buffer.append('@').append(Integer.toHexString(hashCode()));
253         buffer.append("(position=").append(position); //$NON-NLS-1$
254         buffer.append(", forwards = ["); //$NON-NLS-1$
255         for (int i = 0; i < forwardReferenceCount - 1; i++)
256                 buffer.append(forwardReferences[i] + ", "); //$NON-NLS-1$
257         if (forwardReferenceCount >= 1)
258                 buffer.append(forwardReferences[forwardReferenceCount-1]);
259         buffer.append("] )"); //$NON-NLS-1$
260         return buffer.toString();
261 }
262 }