001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.codegen;
011:
012: import java.text.MessageFormat;
013:
014: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
015: import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
016:
017: public class StackMapFrame {
018: public static final int USED = 1;
019: public static final int SAME_FRAME = 0;
020: public static final int CHOP_FRAME = 1;
021: public static final int APPEND_FRAME = 2;
022: public static final int SAME_FRAME_EXTENDED = 3;
023: public static final int FULL_FRAME = 4;
024: public static final int SAME_LOCALS_1_STACK_ITEMS = 5;
025: public static final int SAME_LOCALS_1_STACK_ITEMS_EXTENDED = 6;
026:
027: public int pc;
028: public int numberOfStackItems;
029: private int numberOfLocals;
030: public int localIndex;
031: public VerificationTypeInfo[] locals;
032: public VerificationTypeInfo[] stackItems;
033: private int numberOfDifferentLocals = -1;
034: public int tagBits;
035:
036: public StackMapFrame(int initialLocalSize) {
037: this .locals = new VerificationTypeInfo[initialLocalSize];
038: this .numberOfLocals = -1;
039: this .numberOfDifferentLocals = -1;
040: }
041:
042: public int getFrameType(StackMapFrame prevFrame) {
043: final int offsetDelta = this .getOffsetDelta(prevFrame);
044: switch (this .numberOfStackItems) {
045: case 0:
046: switch (this .numberOfDifferentLocals(prevFrame)) {
047: case 0:
048: return offsetDelta <= 63 ? SAME_FRAME
049: : SAME_FRAME_EXTENDED;
050: case 1:
051: case 2:
052: case 3:
053: return APPEND_FRAME;
054: case -1:
055: case -2:
056: case -3:
057: return CHOP_FRAME;
058: }
059: break;
060: case 1:
061: switch (this .numberOfDifferentLocals(prevFrame)) {
062: case 0:
063: return offsetDelta <= 63 ? SAME_LOCALS_1_STACK_ITEMS
064: : SAME_LOCALS_1_STACK_ITEMS_EXTENDED;
065: }
066: }
067: return FULL_FRAME;
068: }
069:
070: public void addLocal(int resolvedPosition, VerificationTypeInfo info) {
071: if (this .locals == null) {
072: this .locals = new VerificationTypeInfo[resolvedPosition + 1];
073: this .locals[resolvedPosition] = info;
074: } else {
075: final int length = this .locals.length;
076: if (resolvedPosition >= length) {
077: System
078: .arraycopy(
079: this .locals,
080: 0,
081: this .locals = new VerificationTypeInfo[resolvedPosition + 1],
082: 0, length);
083: }
084: this .locals[resolvedPosition] = info;
085: }
086: }
087:
088: public void addStackItem(VerificationTypeInfo info) {
089: if (info == null) {
090: throw new IllegalArgumentException("info cannot be null"); //$NON-NLS-1$
091: }
092: if (this .stackItems == null) {
093: this .stackItems = new VerificationTypeInfo[1];
094: this .stackItems[0] = info;
095: this .numberOfStackItems = 1;
096: } else {
097: final int length = this .stackItems.length;
098: if (this .numberOfStackItems == length) {
099: System
100: .arraycopy(
101: this .stackItems,
102: 0,
103: this .stackItems = new VerificationTypeInfo[length + 1],
104: 0, length);
105: }
106: this .stackItems[this .numberOfStackItems++] = info;
107: }
108: }
109:
110: public void addStackItem(TypeBinding binding) {
111: if (this .stackItems == null) {
112: this .stackItems = new VerificationTypeInfo[1];
113: this .stackItems[0] = new VerificationTypeInfo(binding);
114: this .numberOfStackItems = 1;
115: } else {
116: final int length = this .stackItems.length;
117: if (this .numberOfStackItems == length) {
118: System
119: .arraycopy(
120: this .stackItems,
121: 0,
122: this .stackItems = new VerificationTypeInfo[length + 1],
123: 0, length);
124: }
125: this .stackItems[this .numberOfStackItems++] = new VerificationTypeInfo(
126: binding);
127: }
128: }
129:
130: public StackMapFrame duplicate() {
131: StackMapFrame result = new StackMapFrame(this .locals.length);
132: result.numberOfLocals = -1;
133: result.numberOfDifferentLocals = -1;
134: result.pc = this .pc;
135: result.numberOfStackItems = this .numberOfStackItems;
136:
137: int length = this .locals == null ? 0 : this .locals.length;
138: if (length != 0) {
139: result.locals = new VerificationTypeInfo[length];
140: for (int i = 0; i < length; i++) {
141: final VerificationTypeInfo verificationTypeInfo = this .locals[i];
142: if (verificationTypeInfo != null) {
143: result.locals[i] = verificationTypeInfo.duplicate();
144: }
145: }
146: }
147: length = this .numberOfStackItems;
148: if (length != 0) {
149: result.stackItems = new VerificationTypeInfo[length];
150: for (int i = 0; i < length; i++) {
151: result.stackItems[i] = this .stackItems[i].duplicate();
152: }
153: }
154: return result;
155: }
156:
157: public int numberOfDifferentLocals(StackMapFrame prevFrame) {
158: if (this .numberOfDifferentLocals != -1)
159: return this .numberOfDifferentLocals;
160: if (prevFrame == null) {
161: this .numberOfDifferentLocals = 0;
162: return 0;
163: }
164: VerificationTypeInfo[] prevLocals = prevFrame.locals;
165: VerificationTypeInfo[] currentLocals = this .locals;
166: int prevLocalsLength = prevLocals == null ? 0
167: : prevLocals.length;
168: int currentLocalsLength = currentLocals == null ? 0
169: : currentLocals.length;
170: int prevNumberOfLocals = prevFrame.getNumberOfLocals();
171: int currentNumberOfLocals = this .getNumberOfLocals();
172:
173: int result = 0;
174: if (prevNumberOfLocals == 0) {
175: if (currentNumberOfLocals != 0) {
176: // need to check if there is a hole in the locals
177: result = currentNumberOfLocals; // append if no hole and currentNumberOfLocals <= 3
178: int counter = 0;
179: for (int i = 0; i < currentLocalsLength
180: && counter < currentNumberOfLocals; i++) {
181: if (currentLocals[i] != null) {
182: switch (currentLocals[i].id()) {
183: case TypeIds.T_double:
184: case TypeIds.T_long:
185: i++;
186: }
187: counter++;
188: } else {
189: result = Integer.MAX_VALUE;
190: this .numberOfDifferentLocals = result;
191: return result;
192: }
193: }
194: }
195: } else if (currentNumberOfLocals == 0) {
196: // need to check if there is a hole in the prev locals
197: int counter = 0;
198: result = -prevNumberOfLocals; // chop frame if no hole and prevNumberOfLocals <= 3
199: for (int i = 0; i < prevLocalsLength
200: && counter < prevNumberOfLocals; i++) {
201: if (prevLocals[i] != null) {
202: switch (prevLocals[i].id()) {
203: case TypeIds.T_double:
204: case TypeIds.T_long:
205: i++;
206: }
207: counter++;
208: } else {
209: result = Integer.MAX_VALUE;
210: this .numberOfDifferentLocals = result;
211: return result;
212: }
213: }
214: } else {
215: // need to see if prevLocals matches with currentLocals
216: int indexInPrevLocals = 0;
217: int indexInCurrentLocals = 0;
218: int currentLocalsCounter = 0;
219: int prevLocalsCounter = 0;
220: currentLocalsLoop: for (; indexInCurrentLocals < currentLocalsLength
221: && currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
222: VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
223: if (currentLocal != null) {
224: currentLocalsCounter++;
225: switch (currentLocal.id()) {
226: case TypeIds.T_double:
227: case TypeIds.T_long:
228: indexInCurrentLocals++; // next entry is null
229: }
230: }
231: for (; indexInPrevLocals < prevLocalsLength
232: && prevLocalsCounter < prevNumberOfLocals; indexInPrevLocals++) {
233: VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
234: if (prevLocal != null) {
235: prevLocalsCounter++;
236: switch (prevLocal.id()) {
237: case TypeIds.T_double:
238: case TypeIds.T_long:
239: indexInPrevLocals++; // next entry is null
240: }
241: }
242: // now we need to check if prevLocal matches with currentLocal
243: // the index must be the same
244: if (equals(prevLocal, currentLocal)
245: && indexInPrevLocals == indexInCurrentLocals) {
246: if (result != 0) {
247: result = Integer.MAX_VALUE;
248: this .numberOfDifferentLocals = result;
249: return result;
250: }
251: } else {
252: // locals at the same location are not equals - this has to be a full frame
253: result = Integer.MAX_VALUE;
254: this .numberOfDifferentLocals = result;
255: return result;
256: }
257: indexInPrevLocals++;
258: continue currentLocalsLoop;
259: }
260: // process remaining current locals
261: if (currentLocal != null) {
262: result++;
263: } else {
264: result = Integer.MAX_VALUE;
265: this .numberOfDifferentLocals = result;
266: return result;
267: }
268: indexInCurrentLocals++;
269: break currentLocalsLoop;
270: }
271: if (currentLocalsCounter < currentNumberOfLocals) {
272: for (; indexInCurrentLocals < currentLocalsLength
273: && currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
274: VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
275: if (currentLocal == null) {
276: result = Integer.MAX_VALUE;
277: this .numberOfDifferentLocals = result;
278: return result;
279: }
280: result++;
281: currentLocalsCounter++;
282: switch (currentLocal.id()) {
283: case TypeIds.T_double:
284: case TypeIds.T_long:
285: indexInCurrentLocals++; // next entry is null
286: }
287: }
288: } else if (prevLocalsCounter < prevNumberOfLocals) {
289: result = -result;
290: // process possible remaining prev locals
291: for (; indexInPrevLocals < prevLocalsLength
292: && prevLocalsCounter < prevNumberOfLocals; indexInPrevLocals++) {
293: VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
294: if (prevLocal == null) {
295: result = Integer.MAX_VALUE;
296: this .numberOfDifferentLocals = result;
297: return result;
298: }
299: result--;
300: prevLocalsCounter++;
301: switch (prevLocal.id()) {
302: case TypeIds.T_double:
303: case TypeIds.T_long:
304: indexInPrevLocals++; // next entry is null
305: }
306: }
307: }
308: }
309: this .numberOfDifferentLocals = result;
310: return result;
311: }
312:
313: public int getNumberOfLocals() {
314: if (this .numberOfLocals != -1) {
315: return this .numberOfLocals;
316: }
317: int result = 0;
318: final int length = this .locals == null ? 0 : this .locals.length;
319: for (int i = 0; i < length; i++) {
320: if (this .locals[i] != null) {
321: switch (this .locals[i].id()) {
322: case TypeIds.T_double:
323: case TypeIds.T_long:
324: i++;
325: }
326: result++;
327: }
328: }
329: this .numberOfLocals = result;
330: return result;
331: }
332:
333: public int getOffsetDelta(StackMapFrame prevFrame) {
334: if (prevFrame == null)
335: return this .pc;
336: return prevFrame.pc == -1 ? this .pc : this .pc - prevFrame.pc
337: - 1;
338: }
339:
340: public String toString() {
341: StringBuffer buffer = new StringBuffer();
342: printFrame(buffer, this );
343: return String.valueOf(buffer);
344: }
345:
346: private void printFrame(StringBuffer buffer, StackMapFrame frame) {
347: String pattern = "[pc : {0} locals: {1} stack items: {2}\nlocals: {3}\nstack: {4}\n]"; //$NON-NLS-1$
348: int localsLength = frame.locals == null ? 0
349: : frame.locals.length;
350: buffer.append(MessageFormat.format(pattern, new String[] {
351: Integer.toString(frame.pc),
352: Integer.toString(frame.getNumberOfLocals()),
353: Integer.toString(frame.numberOfStackItems),
354: print(frame.locals, localsLength),
355: print(frame.stackItems, frame.numberOfStackItems) }));
356: }
357:
358: private String print(VerificationTypeInfo[] infos, int length) {
359: StringBuffer buffer = new StringBuffer();
360: buffer.append('[');
361: if (infos != null) {
362: for (int i = 0; i < length; i++) {
363: if (i != 0)
364: buffer.append(',');
365: VerificationTypeInfo verificationTypeInfo = infos[i];
366: if (verificationTypeInfo == null) {
367: buffer.append("top"); //$NON-NLS-1$
368: continue;
369: }
370: buffer.append(verificationTypeInfo);
371: }
372: }
373: buffer.append(']');
374: return String.valueOf(buffer);
375: }
376:
377: public void putLocal(int resolvedPosition, VerificationTypeInfo info) {
378: if (this .locals == null) {
379: this .locals = new VerificationTypeInfo[resolvedPosition + 1];
380: this .locals[resolvedPosition] = info;
381: } else {
382: final int length = this .locals.length;
383: if (resolvedPosition >= length) {
384: System
385: .arraycopy(
386: this .locals,
387: 0,
388: this .locals = new VerificationTypeInfo[resolvedPosition + 1],
389: 0, length);
390: }
391: this .locals[resolvedPosition] = info;
392: }
393: }
394:
395: public void replaceWithElementType() {
396: VerificationTypeInfo info = this .stackItems[this .numberOfStackItems - 1];
397: VerificationTypeInfo info2 = info.duplicate();
398: info2.replaceWithElementType();
399: this .stackItems[this .numberOfStackItems - 1] = info2;
400: }
401:
402: public int getIndexOfDifferentLocals(int differentLocalsCount) {
403: for (int i = this .locals.length - 1; i >= 0; i--) {
404: VerificationTypeInfo currentLocal = this .locals[i];
405: if (currentLocal == null) {
406: // check the previous slot
407: continue;
408: } else {
409: differentLocalsCount--;
410: }
411: if (differentLocalsCount == 0) {
412: return i;
413: }
414: }
415: return 0;
416: }
417:
418: private boolean equals(VerificationTypeInfo info,
419: VerificationTypeInfo info2) {
420: if (info == null) {
421: return info2 == null;
422: }
423: if (info2 == null)
424: return false;
425: return info.equals(info2);
426: }
427: }
|