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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.codegen;
13 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
14 import org.eclipse.jdt.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;
28 // for creating labels ahead of code generation
31 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
33 public Label(CodeStream codeStream) {
34 this.codeStream = codeStream;
37 * Add a forward refrence for the array.
39 void addForwardReference(int iPos) {
41 if (forwardReferenceCount >= (length = forwardReferences.length))
42 System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length);
43 forwardReferences[forwardReferenceCount++] = iPos;
46 * Add a forward refrence for the array.
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);
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;
61 * Put down a reference to the array at the location in the codestream.
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;
71 * Position is set. Write it if it is not a wide branch.
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);
77 codeStream.writeSignedShort(offset);
81 * No support for wide branches yet
84 if (position == POS_NOT_SET) {
85 addForwardReference(codeStream.position);
86 // Leave 4 bytes free to generate the jump offset afterwards
88 codeStream.position += 4;
89 codeStream.classFileOffset += 4;
90 } else { //Position is set. Write it!
91 codeStream.writeSignedWord(position - codeStream.position + 1);
97 public boolean hasForwardReferences() {
98 return forwardReferenceCount != 0;
101 * Some placed labels might be branching to a goto bytecode which we can optimize better.
103 public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) {
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()){
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);
125 Code required to optimized unreachable gotos.
126 label.position = POS_NOT_SET;
129 break; // same target labels should be contiguous
133 public void initialize(CodeStream stream) {
134 this.codeStream = stream;
135 this.position = POS_NOT_SET;
136 this.forwardReferenceCount = 0;
138 public boolean isStandardLabel(){
142 * Place the label. If we have forward references resolve them.
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$
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
161 int index = codeStream.pcToSourceMapSize - 1;
162 while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) {
163 codeStream.pcToSourceMap[index--][1] = position;
166 // Beginning of new code
167 int index = codeStream.pcToSourceMapSize - 2;
168 if (codeStream.lastEntryPC == oldPosition) {
169 codeStream.lastEntryPC = position;
171 if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
172 codeStream.pcToSourceMapSize-=2;
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;
185 if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) {
186 local.initializationPCs[(local.initializationCount - 1) << 1] = position;
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);
198 if (this.codeStream.wideMode) {
200 codeStream.writeSignedWord(forwardReferences[i], offset);
202 codeStream.writeSignedShort(forwardReferences[i], offset);
205 codeStream.writeSignedShort(forwardReferences[i], offset);
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);
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);
229 if (this.codeStream.wideMode) {
231 codeStream.writeSignedWord(forwardPosition, offset);
233 codeStream.writeSignedShort(forwardPosition, offset);
236 codeStream.writeSignedShort(forwardPosition, offset);
246 * Print out the receiver
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();