KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > codegen > BranchLabel


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.codegen;
12
13 import java.util.Arrays JavaDoc;
14
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
17
18 public class BranchLabel extends Label {
19     
20     private int[] forwardReferences = new int[10]; // Add an overflow check here.
21
private int forwardReferenceCount = 0;
22     BranchLabel delegate; //
23

24     // Label tagbits
25
public int tagBits;
26     public final static int WIDE = 1;
27     public final static int USED = 2;
28     
29 public BranchLabel() {
30     // for creating labels ahead of code generation
31
}
32
33 /**
34  * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
35  */

36 public BranchLabel(CodeStream codeStream) {
37     super(codeStream);
38 }
39
40 /**
41  * Add a forward refrence for the array.
42  */

43 void addForwardReference(int pos) {
44     if (this.delegate != null) {
45         this.delegate.addForwardReference(pos);
46         return;
47     }
48     final int count = this.forwardReferenceCount;
49     if (count >= 1) {
50         int previousValue = this.forwardReferences[count - 1];
51         if (previousValue < pos) {
52             int length;
53             if (count >= (length = this.forwardReferences.length))
54                 System.arraycopy(this.forwardReferences, 0, (this.forwardReferences = new int[2*length]), 0, length);
55             this.forwardReferences[this.forwardReferenceCount++] = pos;
56         } else if (previousValue > pos) {
57             int[] refs = this.forwardReferences;
58             // check for duplicates
59
for (int i = 0, max = this.forwardReferenceCount; i < max; i++) {
60                 if (refs[i] == pos) return; // already recorded
61
}
62             int length;
63             if (count >= (length = refs.length))
64                 System.arraycopy(refs, 0, (this.forwardReferences = new int[2*length]), 0, length);
65             this.forwardReferences[this.forwardReferenceCount++] = pos;
66             Arrays.sort(this.forwardReferences, 0, this.forwardReferenceCount);
67         }
68     } else {
69         int length;
70         if (count >= (length = this.forwardReferences.length))
71             System.arraycopy(this.forwardReferences, 0, (this.forwardReferences = new int[2*length]), 0, length);
72         this.forwardReferences[this.forwardReferenceCount++] = pos;
73     }
74 }
75
76 /**
77  * Makes the current label inline all references to the other label
78  */

79 public void becomeDelegateFor(BranchLabel otherLabel) {
80     // other label is delegating to receiver from now on
81
otherLabel.delegate = this;
82     
83     // all existing forward refs to other label are inlined into current label
84
final int otherCount = otherLabel.forwardReferenceCount;
85     if (otherCount == 0) return;
86     // need to merge the two sorted arrays of forward references
87
int[] mergedForwardReferences = new int[this.forwardReferenceCount + otherCount];
88     int indexInMerge = 0;
89     int j = 0;
90     int i = 0;
91     int max = this.forwardReferenceCount;
92     int max2 = otherLabel.forwardReferenceCount;
93     loop1 : for (; i < max; i++) {
94         final int value1 = this.forwardReferences[i];
95         for (; j < max2; j++) {
96             final int value2 = otherLabel.forwardReferences[j];
97             if (value1 < value2) {
98                 mergedForwardReferences[indexInMerge++] = value1;
99                 continue loop1;
100             } else if (value1 == value2) {
101                 mergedForwardReferences[indexInMerge++] = value1;
102                 j++;
103                 continue loop1;
104             } else {
105                 mergedForwardReferences[indexInMerge++] = value2;
106             }
107         }
108         mergedForwardReferences[indexInMerge++] = value1;
109     }
110     for (; j < max2; j++) {
111         mergedForwardReferences[indexInMerge++] = otherLabel.forwardReferences[j];
112     }
113     this.forwardReferences = mergedForwardReferences;
114     this.forwardReferenceCount = indexInMerge;
115 }
116
117 /*
118 * Put down a reference to the array at the location in the codestream.
119 */

120 void branch() {
121     this.tagBits |= BranchLabel.USED;
122     if (this.delegate != null) {
123         this.delegate.branch();
124         return;
125     }
126     if (this.position == Label.POS_NOT_SET) {
127         addForwardReference(this.codeStream.position);
128         // Leave two bytes free to generate the jump afterwards
129
this.codeStream.position += 2;
130         this.codeStream.classFileOffset += 2;
131     } else {
132         /*
133          * Position is set. Write it if it is not a wide branch.
134          */

135         this.codeStream.writePosition(this);
136     }
137 }
138
139 /*
140 * No support for wide branches yet
141 */

142 void branchWide() {
143     this.tagBits |= BranchLabel.USED;
144     if (this.delegate != null) {
145         this.delegate.branchWide();
146         return;
147     }
148     if (this.position == Label.POS_NOT_SET) {
149         addForwardReference(this.codeStream.position);
150         // Leave 4 bytes free to generate the jump offset afterwards
151
this.tagBits |= BranchLabel.WIDE;
152         this.codeStream.position += 4;
153         this.codeStream.classFileOffset += 4;
154     } else { //Position is set. Write it!
155
this.codeStream.writeWidePosition(this);
156     }
157 }
158
159 public int forwardReferenceCount() {
160     if (this.delegate != null) this.delegate.forwardReferenceCount();
161     return forwardReferenceCount;
162 }
163 public int[] forwardReferences() {
164     if (this.delegate != null) this.delegate.forwardReferences();
165     return forwardReferences;
166 }
167 public void initialize(CodeStream stream) {
168     this.codeStream = stream;
169     this.position = Label.POS_NOT_SET;
170     this.forwardReferenceCount = 0;
171     this.delegate = null;
172 }
173 public boolean isCaseLabel() {
174     return false;
175 }
176 public boolean isStandardLabel(){
177     return true;
178 }
179
180 /*
181 * Place the label. If we have forward references resolve them.
182 */

183 public void place() { // Currently lacking wide support.
184
if (CodeStream.DEBUG) System.out.println("\t\t\t\t<place at: "+this.codeStream.position+" - "+ this); //$NON-NLS-1$ //$NON-NLS-2$
185
// if ((this.tagBits & USED) == 0 && this.forwardReferenceCount == 0) {
186
// return;
187
// }
188

189     //TODO how can position be set already ? cannot place more than once
190
if (this.position == Label.POS_NOT_SET) {
191         if ((this.tagBits & BranchLabel.USED) != 0 || this.forwardReferenceCount != 0) {
192             this.position = this.codeStream.getPosition();
193         } else {
194             this.position = this.codeStream.position;
195         }
196         this.codeStream.addLabel(this);
197         int oldPosition = this.position;
198         boolean isOptimizedBranch = false;
199         if (this.forwardReferenceCount != 0) {
200             isOptimizedBranch = (this.forwardReferences[this.forwardReferenceCount - 1] + 2 == this.position) && (this.codeStream.bCodeStream[this.codeStream.classFileOffset - 3] == Opcodes.OPC_goto);
201             if (isOptimizedBranch) {
202                 if (this.codeStream.lastAbruptCompletion == this.position) {
203                     this.codeStream.lastAbruptCompletion = -1;
204                 }
205                 this.codeStream.position = (this.position -= 3);
206                 this.codeStream.classFileOffset -= 3;
207                 this.forwardReferenceCount--;
208                 if (this.codeStream.lastEntryPC == oldPosition) {
209                     this.codeStream.lastEntryPC = this.position;
210                 }
211                 // end of new code
212
if ((this.codeStream.generateAttributes & (ClassFileConstants.ATTR_VARS | ClassFileConstants.ATTR_STACK_MAP)) != 0) {
213                     LocalVariableBinding locals[] = this.codeStream.locals;
214                     for (int i = 0, max = locals.length; i < max; i++) {
215                         LocalVariableBinding local = locals[i];
216                         if ((local != null) && (local.initializationCount > 0)) {
217                             if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) {
218                                 // we want to prevent interval of size 0 to have a negative size.
219
// see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute
220
local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = this.position;
221                             }
222                             if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
223                                 local.initializationPCs[(local.initializationCount - 1) << 1] = this.position;
224                             }
225                         }
226                     }
227                 }
228                 if ((this.codeStream.generateAttributes & ClassFileConstants.ATTR_LINES) != 0) {
229                     // we need to remove all entries that is beyond this.position inside the pcToSourcerMap table
230
this.codeStream.removeUnusedPcToSourceMapEntries();
231                 }
232             }
233         }
234         for (int i = 0; i < this.forwardReferenceCount; i++) {
235             this.codeStream.writePosition(this, this.forwardReferences[i]);
236         }
237         // For all labels placed at that position we check if we need to rewrite the jump
238
// offset. It is the case each time a label had a forward reference to the current position.
239
// Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details.
240
if (isOptimizedBranch) {
241             this.codeStream.optimizeBranch(oldPosition, this);
242         }
243     }
244 }
245
246 /**
247  * Print out the receiver
248  */

249 public String JavaDoc toString() {
250     String JavaDoc basic = getClass().getName();
251     basic = basic.substring(basic.lastIndexOf('.')+1);
252     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(basic);
253     buffer.append('@').append(Integer.toHexString(hashCode()));
254     buffer.append("(position=").append(this.position); //$NON-NLS-1$
255
if (this.delegate != null) buffer.append("delegate=").append(this.delegate); //$NON-NLS-1$
256
buffer.append(", forwards = ["); //$NON-NLS-1$
257
for (int i = 0; i < this.forwardReferenceCount - 1; i++)
258         buffer.append(this.forwardReferences[i] + ", "); //$NON-NLS-1$
259
if (this.forwardReferenceCount >= 1)
260         buffer.append(this.forwardReferences[this.forwardReferenceCount-1]);
261     buffer.append("] )"); //$NON-NLS-1$
262
return buffer.toString();
263 }
264 }
265
Popular Tags