001: /*
002: * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.jvm;
027:
028: import java.util.*;
029:
030: import com.sun.tools.javac.tree.*;
031: import com.sun.tools.javac.util.*;
032: import com.sun.tools.javac.util.List;
033: import com.sun.tools.javac.tree.JCTree.*;
034:
035: /** This class contains the CharacterRangeTable for some method
036: * and the hashtable for mapping trees or lists of trees to their
037: * ending positions.
038: *
039: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
040: * you write code that depends on this, you do so at your own risk.
041: * This code and its internal interfaces are subject to change or
042: * deletion without notice.</b>
043: */
044: @Version("@(#)CRTable.java 1.33 07/06/14")
045: public class CRTable implements CRTFlags {
046:
047: private final boolean crtDebug = false;
048:
049: /** The list of CRTable entries.
050: */
051: private ListBuffer<CRTEntry> entries = new ListBuffer<CRTEntry>();
052:
053: /** The hashtable for source positions.
054: */
055: private Map<Object, SourceRange> positions = new HashMap<Object, SourceRange>();
056:
057: /** The hashtable for ending positions stored in the parser.
058: */
059: private Map<JCTree, Integer> endPositions;
060:
061: /** The tree of the method this table is intended for.
062: * We should traverse this tree to get source ranges.
063: */
064: JCTree.JCMethodDecl methodTree;
065:
066: /** Constructor
067: */
068: public CRTable(JCTree.JCMethodDecl tree,
069: Map<JCTree, Integer> endPositions) {
070: this .methodTree = tree;
071: this .endPositions = endPositions;
072: }
073:
074: /** Create a new CRTEntry and add it to the entries.
075: * @param tree The tree or the list of trees for which
076: * we are storing the code pointers.
077: * @param flags The set of flags designating type of the entry.
078: * @param startPc The starting code position.
079: * @param endPc The ending code position.
080: */
081: public void put(Object tree, int flags, int startPc, int endPc) {
082: entries.append(new CRTEntry(tree, flags, startPc, endPc));
083: }
084:
085: /** Compute source positions and write CRT to the databuf.
086: * @param databuf The buffer to write bytecodes to.
087: */
088: public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap,
089: Log log) {
090:
091: int crtEntries = 0;
092:
093: // compute source positions for the method
094: new SourceComputer().csp(methodTree);
095:
096: for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
097:
098: CRTEntry entry = l.head;
099:
100: // eliminate entries that do not produce bytecodes:
101: // for example, empty blocks and statements
102: if (entry.startPc == entry.endPc)
103: continue;
104:
105: SourceRange pos = positions.get(entry.tree);
106: assert pos != null : "CRT: tree source positions are undefined";
107: if ((pos.startPos == Position.NOPOS)
108: || (pos.endPos == Position.NOPOS))
109: continue;
110:
111: if (crtDebug) {
112: System.out.println("Tree: " + entry.tree + ", type:"
113: + getTypes(entry.flags));
114: System.out.print("Start: pos = " + pos.startPos
115: + ", pc = " + entry.startPc);
116: }
117:
118: // encode startPos into line/column representation
119: int startPos = encodePosition(pos.startPos, lineMap, log);
120: if (startPos == Position.NOPOS)
121: continue;
122:
123: if (crtDebug) {
124: System.out.print("End: pos = " + pos.endPos
125: + ", pc = " + (entry.endPc - 1));
126: }
127:
128: // encode endPos into line/column representation
129: int endPos = encodePosition(pos.endPos, lineMap, log);
130: if (endPos == Position.NOPOS)
131: continue;
132:
133: // write attribute
134: databuf.appendChar(entry.startPc);
135: // 'endPc - 1' because endPc actually points to start of the next command
136: databuf.appendChar(entry.endPc - 1);
137: databuf.appendInt(startPos);
138: databuf.appendInt(endPos);
139: databuf.appendChar(entry.flags);
140:
141: crtEntries++;
142: }
143:
144: return crtEntries;
145: }
146:
147: /** Return the number of the entries.
148: */
149: public int length() {
150: return entries.length();
151: }
152:
153: /** Return string describing flags enabled.
154: */
155: private String getTypes(int flags) {
156: String types = "";
157: if ((flags & CRT_STATEMENT) != 0)
158: types += " CRT_STATEMENT";
159: if ((flags & CRT_BLOCK) != 0)
160: types += " CRT_BLOCK";
161: if ((flags & CRT_ASSIGNMENT) != 0)
162: types += " CRT_ASSIGNMENT";
163: if ((flags & CRT_FLOW_CONTROLLER) != 0)
164: types += " CRT_FLOW_CONTROLLER";
165: if ((flags & CRT_FLOW_TARGET) != 0)
166: types += " CRT_FLOW_TARGET";
167: if ((flags & CRT_INVOKE) != 0)
168: types += " CRT_INVOKE";
169: if ((flags & CRT_CREATE) != 0)
170: types += " CRT_CREATE";
171: if ((flags & CRT_BRANCH_TRUE) != 0)
172: types += " CRT_BRANCH_TRUE";
173: if ((flags & CRT_BRANCH_FALSE) != 0)
174: types += " CRT_BRANCH_FALSE";
175: return types;
176: }
177:
178: /** Source file positions in CRT are integers in the format:
179: * line-number << LINESHIFT + column-number
180: */
181: private int encodePosition(int pos, Position.LineMap lineMap,
182: Log log) {
183: int line = lineMap.getLineNumber(pos);
184: int col = lineMap.getColumnNumber(pos);
185: int new_pos = Position.encodePosition(line, col);
186: if (crtDebug) {
187: System.out.println(", line = " + line + ", column = " + col
188: + ", new_pos = " + new_pos);
189: }
190: if (new_pos == Position.NOPOS)
191: log.warning(pos, "position.overflow", line);
192:
193: return new_pos;
194: }
195:
196: /* ************************************************************************
197: * Traversal methods
198: *************************************************************************/
199:
200: /**
201: * This class contains methods to compute source positions for trees.
202: * Extends Tree.Visitor to traverse the abstract syntax tree.
203: */
204: class SourceComputer extends JCTree.Visitor {
205:
206: /** The result of the tree traversal methods.
207: */
208: SourceRange result;
209:
210: /** Visitor method: compute source positions for a single node.
211: */
212: public SourceRange csp(JCTree tree) {
213: if (tree == null)
214: return null;
215: tree.accept(this );
216: if (result != null) {
217: positions.put(tree, result);
218: }
219: return result;
220: }
221:
222: /** Visitor method: compute source positions for a list of nodes.
223: */
224: public SourceRange csp(List<? extends JCTree> trees) {
225: if ((trees == null) || !(trees.nonEmpty()))
226: return null;
227: SourceRange list_sr = new SourceRange();
228: for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
229: list_sr.mergeWith(csp(l.head));
230: }
231: positions.put(trees, list_sr);
232: return list_sr;
233: }
234:
235: /** Visitor method: compute source positions for
236: * a list of case blocks of switch statements.
237: */
238: public SourceRange cspCases(List<JCCase> trees) {
239: if ((trees == null) || !(trees.nonEmpty()))
240: return null;
241: SourceRange list_sr = new SourceRange();
242: for (List<JCCase> l = trees; l.nonEmpty(); l = l.tail) {
243: list_sr.mergeWith(csp(l.head));
244: }
245: positions.put(trees, list_sr);
246: return list_sr;
247: }
248:
249: /** Visitor method: compute source positions for
250: * a list of catch clauses in try statements.
251: */
252: public SourceRange cspCatchers(List<JCCatch> trees) {
253: if ((trees == null) || !(trees.nonEmpty()))
254: return null;
255: SourceRange list_sr = new SourceRange();
256: for (List<JCCatch> l = trees; l.nonEmpty(); l = l.tail) {
257: list_sr.mergeWith(csp(l.head));
258: }
259: positions.put(trees, list_sr);
260: return list_sr;
261: }
262:
263: public void visitMethodDef(JCMethodDecl tree) {
264: SourceRange sr = new SourceRange(startPos(tree),
265: endPos(tree));
266: sr.mergeWith(csp(tree.body));
267: result = sr;
268: }
269:
270: public void visitVarDef(JCVariableDecl tree) {
271: SourceRange sr = new SourceRange(startPos(tree),
272: endPos(tree));
273: csp(tree.vartype);
274: sr.mergeWith(csp(tree.init));
275: result = sr;
276: }
277:
278: public void visitSkip(JCSkip tree) {
279: // endPos is the same as startPos for the empty statement
280: SourceRange sr = new SourceRange(startPos(tree),
281: startPos(tree));
282: result = sr;
283: }
284:
285: public void visitBlock(JCBlock tree) {
286: SourceRange sr = new SourceRange(startPos(tree),
287: endPos(tree));
288: csp(tree.stats); // doesn't compare because block's ending position is defined
289: result = sr;
290: }
291:
292: public void visitDoLoop(JCDoWhileLoop tree) {
293: SourceRange sr = new SourceRange(startPos(tree),
294: endPos(tree));
295: sr.mergeWith(csp(tree.body));
296: sr.mergeWith(csp(tree.cond));
297: result = sr;
298: }
299:
300: public void visitWhileLoop(JCWhileLoop tree) {
301: SourceRange sr = new SourceRange(startPos(tree),
302: endPos(tree));
303: sr.mergeWith(csp(tree.cond));
304: sr.mergeWith(csp(tree.body));
305: result = sr;
306: }
307:
308: public void visitForLoop(JCForLoop tree) {
309: SourceRange sr = new SourceRange(startPos(tree),
310: endPos(tree));
311: sr.mergeWith(csp(tree.init));
312: sr.mergeWith(csp(tree.cond));
313: sr.mergeWith(csp(tree.step));
314: sr.mergeWith(csp(tree.body));
315: result = sr;
316: }
317:
318: public void visitForeachLoop(JCEnhancedForLoop tree) {
319: SourceRange sr = new SourceRange(startPos(tree),
320: endPos(tree));
321: sr.mergeWith(csp(tree.var));
322: sr.mergeWith(csp(tree.expr));
323: sr.mergeWith(csp(tree.body));
324: result = sr;
325: }
326:
327: public void visitLabelled(JCLabeledStatement tree) {
328: SourceRange sr = new SourceRange(startPos(tree),
329: endPos(tree));
330: sr.mergeWith(csp(tree.body));
331: result = sr;
332: }
333:
334: public void visitSwitch(JCSwitch tree) {
335: SourceRange sr = new SourceRange(startPos(tree),
336: endPos(tree));
337: sr.mergeWith(csp(tree.selector));
338: sr.mergeWith(cspCases(tree.cases));
339: result = sr;
340: }
341:
342: public void visitCase(JCCase tree) {
343: SourceRange sr = new SourceRange(startPos(tree),
344: endPos(tree));
345: sr.mergeWith(csp(tree.pat));
346: sr.mergeWith(csp(tree.stats));
347: result = sr;
348: }
349:
350: public void visitSynchronized(JCSynchronized tree) {
351: SourceRange sr = new SourceRange(startPos(tree),
352: endPos(tree));
353: sr.mergeWith(csp(tree.lock));
354: sr.mergeWith(csp(tree.body));
355: result = sr;
356: }
357:
358: public void visitTry(JCTry tree) {
359: SourceRange sr = new SourceRange(startPos(tree),
360: endPos(tree));
361: sr.mergeWith(csp(tree.body));
362: sr.mergeWith(cspCatchers(tree.catchers));
363: sr.mergeWith(csp(tree.finalizer));
364: result = sr;
365: }
366:
367: public void visitCatch(JCCatch tree) {
368: SourceRange sr = new SourceRange(startPos(tree),
369: endPos(tree));
370: sr.mergeWith(csp(tree.param));
371: sr.mergeWith(csp(tree.body));
372: result = sr;
373: }
374:
375: public void visitConditional(JCConditional tree) {
376: SourceRange sr = new SourceRange(startPos(tree),
377: endPos(tree));
378: sr.mergeWith(csp(tree.cond));
379: sr.mergeWith(csp(tree.truepart));
380: sr.mergeWith(csp(tree.falsepart));
381: result = sr;
382: }
383:
384: public void visitIf(JCIf tree) {
385: SourceRange sr = new SourceRange(startPos(tree),
386: endPos(tree));
387: sr.mergeWith(csp(tree.cond));
388: sr.mergeWith(csp(tree.thenpart));
389: sr.mergeWith(csp(tree.elsepart));
390: result = sr;
391: }
392:
393: public void visitExec(JCExpressionStatement tree) {
394: SourceRange sr = new SourceRange(startPos(tree),
395: endPos(tree));
396: sr.mergeWith(csp(tree.expr));
397: result = sr;
398: }
399:
400: public void visitBreak(JCBreak tree) {
401: SourceRange sr = new SourceRange(startPos(tree),
402: endPos(tree));
403: result = sr;
404: }
405:
406: public void visitContinue(JCContinue tree) {
407: SourceRange sr = new SourceRange(startPos(tree),
408: endPos(tree));
409: result = sr;
410: }
411:
412: public void visitReturn(JCReturn tree) {
413: SourceRange sr = new SourceRange(startPos(tree),
414: endPos(tree));
415: sr.mergeWith(csp(tree.expr));
416: result = sr;
417: }
418:
419: public void visitThrow(JCThrow tree) {
420: SourceRange sr = new SourceRange(startPos(tree),
421: endPos(tree));
422: sr.mergeWith(csp(tree.expr));
423: result = sr;
424: }
425:
426: public void visitAssert(JCAssert tree) {
427: SourceRange sr = new SourceRange(startPos(tree),
428: endPos(tree));
429: sr.mergeWith(csp(tree.cond));
430: sr.mergeWith(csp(tree.detail));
431: result = sr;
432: }
433:
434: public void visitApply(JCMethodInvocation tree) {
435: SourceRange sr = new SourceRange(startPos(tree),
436: endPos(tree));
437: sr.mergeWith(csp(tree.meth));
438: sr.mergeWith(csp(tree.args));
439: result = sr;
440: }
441:
442: public void visitNewClass(JCNewClass tree) {
443: SourceRange sr = new SourceRange(startPos(tree),
444: endPos(tree));
445: sr.mergeWith(csp(tree.encl));
446: sr.mergeWith(csp(tree.clazz));
447: sr.mergeWith(csp(tree.args));
448: sr.mergeWith(csp(tree.def));
449: result = sr;
450: }
451:
452: public void visitNewArray(JCNewArray tree) {
453: SourceRange sr = new SourceRange(startPos(tree),
454: endPos(tree));
455: sr.mergeWith(csp(tree.elemtype));
456: sr.mergeWith(csp(tree.dims));
457: sr.mergeWith(csp(tree.elems));
458: result = sr;
459: }
460:
461: public void visitParens(JCParens tree) {
462: SourceRange sr = new SourceRange(startPos(tree),
463: endPos(tree));
464: sr.mergeWith(csp(tree.expr));
465: result = sr;
466: }
467:
468: public void visitAssign(JCAssign tree) {
469: SourceRange sr = new SourceRange(startPos(tree),
470: endPos(tree));
471: sr.mergeWith(csp(tree.lhs));
472: sr.mergeWith(csp(tree.rhs));
473: result = sr;
474: }
475:
476: public void visitAssignop(JCAssignOp tree) {
477: SourceRange sr = new SourceRange(startPos(tree),
478: endPos(tree));
479: sr.mergeWith(csp(tree.lhs));
480: sr.mergeWith(csp(tree.rhs));
481: result = sr;
482: }
483:
484: public void visitUnary(JCUnary tree) {
485: SourceRange sr = new SourceRange(startPos(tree),
486: endPos(tree));
487: sr.mergeWith(csp(tree.arg));
488: result = sr;
489: }
490:
491: public void visitBinary(JCBinary tree) {
492: SourceRange sr = new SourceRange(startPos(tree),
493: endPos(tree));
494: sr.mergeWith(csp(tree.lhs));
495: sr.mergeWith(csp(tree.rhs));
496: result = sr;
497: }
498:
499: public void visitTypeCast(JCTypeCast tree) {
500: SourceRange sr = new SourceRange(startPos(tree),
501: endPos(tree));
502: sr.mergeWith(csp(tree.clazz));
503: sr.mergeWith(csp(tree.expr));
504: result = sr;
505: }
506:
507: public void visitTypeTest(JCInstanceOf tree) {
508: SourceRange sr = new SourceRange(startPos(tree),
509: endPos(tree));
510: sr.mergeWith(csp(tree.expr));
511: sr.mergeWith(csp(tree.clazz));
512: result = sr;
513: }
514:
515: public void visitIndexed(JCArrayAccess tree) {
516: SourceRange sr = new SourceRange(startPos(tree),
517: endPos(tree));
518: sr.mergeWith(csp(tree.indexed));
519: sr.mergeWith(csp(tree.index));
520: result = sr;
521: }
522:
523: public void visitSelect(JCFieldAccess tree) {
524: SourceRange sr = new SourceRange(startPos(tree),
525: endPos(tree));
526: sr.mergeWith(csp(tree.selected));
527: result = sr;
528: }
529:
530: public void visitIdent(JCIdent tree) {
531: SourceRange sr = new SourceRange(startPos(tree),
532: endPos(tree));
533: result = sr;
534: }
535:
536: public void visitLiteral(JCLiteral tree) {
537: SourceRange sr = new SourceRange(startPos(tree),
538: endPos(tree));
539: result = sr;
540: }
541:
542: public void visitTypeIdent(JCPrimitiveTypeTree tree) {
543: SourceRange sr = new SourceRange(startPos(tree),
544: endPos(tree));
545: result = sr;
546: }
547:
548: public void visitTypeArray(JCArrayTypeTree tree) {
549: SourceRange sr = new SourceRange(startPos(tree),
550: endPos(tree));
551: sr.mergeWith(csp(tree.elemtype));
552: result = sr;
553: }
554:
555: public void visitTypeApply(JCTypeApply tree) {
556: SourceRange sr = new SourceRange(startPos(tree),
557: endPos(tree));
558: sr.mergeWith(csp(tree.clazz));
559: sr.mergeWith(csp(tree.arguments));
560: result = sr;
561: }
562:
563: public void visitTypeParameter(JCTypeParameter tree) {
564: SourceRange sr = new SourceRange(startPos(tree),
565: endPos(tree));
566: sr.mergeWith(csp(tree.bounds));
567: result = sr;
568: }
569:
570: public void visitWildcard(JCWildcard tree) {
571: result = null;
572: }
573:
574: public void visitErroneous(JCErroneous tree) {
575: result = null;
576: }
577:
578: public void visitTree(JCTree tree) {
579: assert false;
580: }
581:
582: /** The start position of given tree.
583: */
584: public int startPos(JCTree tree) {
585: if (tree == null)
586: return Position.NOPOS;
587: return tree.pos;
588: }
589:
590: /** The end position of given tree, if it has
591: * defined endpos, NOPOS otherwise.
592: */
593: public int endPos(JCTree tree) {
594: if (tree == null)
595: return Position.NOPOS;
596: if (tree.getTag() == JCTree.BLOCK)
597: return ((JCBlock) tree).endpos;
598: Integer endpos = endPositions.get(tree);
599: if (endpos != null)
600: return endpos.intValue();
601: return Position.NOPOS;
602: }
603: }
604:
605: /** This class contains a CharacterRangeTableEntry.
606: */
607: static class CRTEntry {
608:
609: /** A tree or a list of trees to obtain source positions.
610: */
611: Object tree;
612:
613: /** The flags described in the CharacterRangeTable spec.
614: */
615: int flags;
616:
617: /** The starting code position of this entry.
618: */
619: int startPc;
620:
621: /** The ending code position of this entry.
622: */
623: int endPc;
624:
625: /** Constructor */
626: CRTEntry(Object tree, int flags, int startPc, int endPc) {
627: this .tree = tree;
628: this .flags = flags;
629: this .startPc = startPc;
630: this .endPc = endPc;
631: }
632: }
633:
634: /** This class contains source positions
635: * for some tree or list of trees.
636: */
637: static class SourceRange {
638:
639: /** The starting source position.
640: */
641: int startPos;
642:
643: /** The ending source position.
644: */
645: int endPos;
646:
647: /** Constructor */
648: SourceRange() {
649: startPos = Position.NOPOS;
650: endPos = Position.NOPOS;
651: }
652:
653: /** Constructor */
654: SourceRange(int startPos, int endPos) {
655: this .startPos = startPos;
656: this .endPos = endPos;
657: }
658:
659: /** Compare the starting and the ending positions
660: * of the source range and combines them assigning
661: * the widest range to this.
662: */
663: SourceRange mergeWith(SourceRange sr) {
664: if (sr == null)
665: return this;
666: if (startPos == Position.NOPOS)
667: startPos = sr.startPos;
668: else if (sr.startPos != Position.NOPOS)
669: startPos = (startPos < sr.startPos ? startPos
670: : sr.startPos);
671: if (endPos == Position.NOPOS)
672: endPos = sr.endPos;
673: else if (sr.endPos != Position.NOPOS)
674: endPos = (endPos > sr.endPos ? endPos : sr.endPos);
675: return this;
676: }
677: }
678:
679: }
|