Mon, 14 Nov 2011 15:11:10 -0800
7106166: (javac) re-factor EndPos parser
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.javac.jvm;
28 import java.util.*;
30 import com.sun.tools.javac.tree.*;
31 import com.sun.tools.javac.util.*;
32 import com.sun.tools.javac.util.List;
33 import com.sun.tools.javac.tree.JCTree.*;
34 import com.sun.tools.javac.parser.EndPosTable;
36 /** This class contains the CharacterRangeTable for some method
37 * and the hashtable for mapping trees or lists of trees to their
38 * ending positions.
39 *
40 * <p><b>This is NOT part of any supported API.
41 * If you write code that depends on this, you do so at your own risk.
42 * This code and its internal interfaces are subject to change or
43 * deletion without notice.</b>
44 */
45 public class CRTable
46 implements CRTFlags {
48 private final boolean crtDebug = false;
50 /** The list of CRTable entries.
51 */
52 private ListBuffer<CRTEntry> entries = new ListBuffer<CRTEntry>();
54 /** The hashtable for source positions.
55 */
56 private Map<Object,SourceRange> positions = new HashMap<Object,SourceRange>();
58 /** The object for ending positions stored in the parser.
59 */
60 private EndPosTable endPosTable;
62 /** The tree of the method this table is intended for.
63 * We should traverse this tree to get source ranges.
64 */
65 JCTree.JCMethodDecl methodTree;
67 /** Constructor
68 */
69 public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) {
70 this.methodTree = tree;
71 this.endPosTable = endPosTable;
72 }
74 /** Create a new CRTEntry and add it to the entries.
75 * @param tree The tree or the list of trees for which
76 * we are storing the code pointers.
77 * @param flags The set of flags designating type of the entry.
78 * @param startPc The starting code position.
79 * @param endPc The ending code position.
80 */
81 public void put(Object tree, int flags, int startPc, int endPc) {
82 entries.append(new CRTEntry(tree, flags, startPc, endPc));
83 }
85 /** Compute source positions and write CRT to the databuf.
86 * @param databuf The buffer to write bytecodes to.
87 */
88 public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) {
90 int crtEntries = 0;
92 // compute source positions for the method
93 new SourceComputer().csp(methodTree);
95 for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
97 CRTEntry entry = l.head;
99 // eliminate entries that do not produce bytecodes:
100 // for example, empty blocks and statements
101 if (entry.startPc == entry.endPc)
102 continue;
104 SourceRange pos = positions.get(entry.tree);
105 Assert.checkNonNull(pos, "CRT: tree source positions are undefined");
106 if ((pos.startPos == Position.NOPOS) || (pos.endPos == Position.NOPOS))
107 continue;
109 if (crtDebug) {
110 System.out.println("Tree: " + entry.tree + ", type:" + getTypes(entry.flags));
111 System.out.print("Start: pos = " + pos.startPos + ", pc = " + entry.startPc);
112 }
114 // encode startPos into line/column representation
115 int startPos = encodePosition(pos.startPos, lineMap, log);
116 if (startPos == Position.NOPOS)
117 continue;
119 if (crtDebug) {
120 System.out.print("End: pos = " + pos.endPos + ", pc = " + (entry.endPc - 1));
121 }
123 // encode endPos into line/column representation
124 int endPos = encodePosition(pos.endPos, lineMap, log);
125 if (endPos == Position.NOPOS)
126 continue;
128 // write attribute
129 databuf.appendChar(entry.startPc);
130 // 'endPc - 1' because endPc actually points to start of the next command
131 databuf.appendChar(entry.endPc - 1);
132 databuf.appendInt(startPos);
133 databuf.appendInt(endPos);
134 databuf.appendChar(entry.flags);
136 crtEntries++;
137 }
139 return crtEntries;
140 }
142 /** Return the number of the entries.
143 */
144 public int length() {
145 return entries.length();
146 }
148 /** Return string describing flags enabled.
149 */
150 private String getTypes(int flags) {
151 String types = "";
152 if ((flags & CRT_STATEMENT) != 0) types += " CRT_STATEMENT";
153 if ((flags & CRT_BLOCK) != 0) types += " CRT_BLOCK";
154 if ((flags & CRT_ASSIGNMENT) != 0) types += " CRT_ASSIGNMENT";
155 if ((flags & CRT_FLOW_CONTROLLER) != 0) types += " CRT_FLOW_CONTROLLER";
156 if ((flags & CRT_FLOW_TARGET) != 0) types += " CRT_FLOW_TARGET";
157 if ((flags & CRT_INVOKE) != 0) types += " CRT_INVOKE";
158 if ((flags & CRT_CREATE) != 0) types += " CRT_CREATE";
159 if ((flags & CRT_BRANCH_TRUE) != 0) types += " CRT_BRANCH_TRUE";
160 if ((flags & CRT_BRANCH_FALSE) != 0) types += " CRT_BRANCH_FALSE";
161 return types;
162 }
164 /** Source file positions in CRT are integers in the format:
165 * line-number << LINESHIFT + column-number
166 */
167 private int encodePosition(int pos, Position.LineMap lineMap, Log log) {
168 int line = lineMap.getLineNumber(pos);
169 int col = lineMap.getColumnNumber(pos);
170 int new_pos = Position.encodePosition(line, col);
171 if (crtDebug) {
172 System.out.println(", line = " + line + ", column = " + col +
173 ", new_pos = " + new_pos);
174 }
175 if (new_pos == Position.NOPOS)
176 log.warning(pos, "position.overflow", line);
178 return new_pos;
179 }
181 /* ************************************************************************
182 * Traversal methods
183 *************************************************************************/
185 /**
186 * This class contains methods to compute source positions for trees.
187 * Extends Tree.Visitor to traverse the abstract syntax tree.
188 */
189 class SourceComputer extends JCTree.Visitor {
191 /** The result of the tree traversal methods.
192 */
193 SourceRange result;
195 /** Visitor method: compute source positions for a single node.
196 */
197 public SourceRange csp(JCTree tree) {
198 if (tree == null) return null;
199 tree.accept(this);
200 if (result != null) {
201 positions.put(tree, result);
202 }
203 return result;
204 }
206 /** Visitor method: compute source positions for a list of nodes.
207 */
208 public SourceRange csp(List<? extends JCTree> trees) {
209 if ((trees == null) || !(trees.nonEmpty())) return null;
210 SourceRange list_sr = new SourceRange();
211 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
212 list_sr.mergeWith(csp(l.head));
213 }
214 positions.put(trees, list_sr);
215 return list_sr;
216 }
218 /** Visitor method: compute source positions for
219 * a list of case blocks of switch statements.
220 */
221 public SourceRange cspCases(List<JCCase> trees) {
222 if ((trees == null) || !(trees.nonEmpty())) return null;
223 SourceRange list_sr = new SourceRange();
224 for (List<JCCase> l = trees; l.nonEmpty(); l = l.tail) {
225 list_sr.mergeWith(csp(l.head));
226 }
227 positions.put(trees, list_sr);
228 return list_sr;
229 }
231 /** Visitor method: compute source positions for
232 * a list of catch clauses in try statements.
233 */
234 public SourceRange cspCatchers(List<JCCatch> trees) {
235 if ((trees == null) || !(trees.nonEmpty())) return null;
236 SourceRange list_sr = new SourceRange();
237 for (List<JCCatch> l = trees; l.nonEmpty(); l = l.tail) {
238 list_sr.mergeWith(csp(l.head));
239 }
240 positions.put(trees, list_sr);
241 return list_sr;
242 }
244 public void visitMethodDef(JCMethodDecl tree) {
245 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
246 sr.mergeWith(csp(tree.body));
247 result = sr;
248 }
250 public void visitVarDef(JCVariableDecl tree) {
251 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
252 csp(tree.vartype);
253 sr.mergeWith(csp(tree.init));
254 result = sr;
255 }
257 public void visitSkip(JCSkip tree) {
258 // endPos is the same as startPos for the empty statement
259 SourceRange sr = new SourceRange(startPos(tree), startPos(tree));
260 result = sr;
261 }
263 public void visitBlock(JCBlock tree) {
264 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
265 csp(tree.stats); // doesn't compare because block's ending position is defined
266 result = sr;
267 }
269 public void visitDoLoop(JCDoWhileLoop tree) {
270 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
271 sr.mergeWith(csp(tree.body));
272 sr.mergeWith(csp(tree.cond));
273 result = sr;
274 }
276 public void visitWhileLoop(JCWhileLoop tree) {
277 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
278 sr.mergeWith(csp(tree.cond));
279 sr.mergeWith(csp(tree.body));
280 result = sr;
281 }
283 public void visitForLoop(JCForLoop tree) {
284 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
285 sr.mergeWith(csp(tree.init));
286 sr.mergeWith(csp(tree.cond));
287 sr.mergeWith(csp(tree.step));
288 sr.mergeWith(csp(tree.body));
289 result = sr;
290 }
292 public void visitForeachLoop(JCEnhancedForLoop tree) {
293 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
294 sr.mergeWith(csp(tree.var));
295 sr.mergeWith(csp(tree.expr));
296 sr.mergeWith(csp(tree.body));
297 result = sr;
298 }
300 public void visitLabelled(JCLabeledStatement tree) {
301 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
302 sr.mergeWith(csp(tree.body));
303 result = sr;
304 }
306 public void visitSwitch(JCSwitch tree) {
307 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
308 sr.mergeWith(csp(tree.selector));
309 sr.mergeWith(cspCases(tree.cases));
310 result = sr;
311 }
313 public void visitCase(JCCase tree) {
314 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
315 sr.mergeWith(csp(tree.pat));
316 sr.mergeWith(csp(tree.stats));
317 result = sr;
318 }
320 public void visitSynchronized(JCSynchronized tree) {
321 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
322 sr.mergeWith(csp(tree.lock));
323 sr.mergeWith(csp(tree.body));
324 result = sr;
325 }
327 public void visitTry(JCTry tree) {
328 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
329 sr.mergeWith(csp(tree.resources));
330 sr.mergeWith(csp(tree.body));
331 sr.mergeWith(cspCatchers(tree.catchers));
332 sr.mergeWith(csp(tree.finalizer));
333 result = sr;
334 }
336 public void visitCatch(JCCatch tree) {
337 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
338 sr.mergeWith(csp(tree.param));
339 sr.mergeWith(csp(tree.body));
340 result = sr;
341 }
343 public void visitConditional(JCConditional tree) {
344 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
345 sr.mergeWith(csp(tree.cond));
346 sr.mergeWith(csp(tree.truepart));
347 sr.mergeWith(csp(tree.falsepart));
348 result = sr;
349 }
351 public void visitIf(JCIf tree) {
352 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
353 sr.mergeWith(csp(tree.cond));
354 sr.mergeWith(csp(tree.thenpart));
355 sr.mergeWith(csp(tree.elsepart));
356 result = sr;
357 }
359 public void visitExec(JCExpressionStatement tree) {
360 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
361 sr.mergeWith(csp(tree.expr));
362 result = sr;
363 }
365 public void visitBreak(JCBreak tree) {
366 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
367 result = sr;
368 }
370 public void visitContinue(JCContinue tree) {
371 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
372 result = sr;
373 }
375 public void visitReturn(JCReturn tree) {
376 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
377 sr.mergeWith(csp(tree.expr));
378 result = sr;
379 }
381 public void visitThrow(JCThrow tree) {
382 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
383 sr.mergeWith(csp(tree.expr));
384 result = sr;
385 }
387 public void visitAssert(JCAssert tree) {
388 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
389 sr.mergeWith(csp(tree.cond));
390 sr.mergeWith(csp(tree.detail));
391 result = sr;
392 }
394 public void visitApply(JCMethodInvocation tree) {
395 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
396 sr.mergeWith(csp(tree.meth));
397 sr.mergeWith(csp(tree.args));
398 result = sr;
399 }
401 public void visitNewClass(JCNewClass tree) {
402 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
403 sr.mergeWith(csp(tree.encl));
404 sr.mergeWith(csp(tree.clazz));
405 sr.mergeWith(csp(tree.args));
406 sr.mergeWith(csp(tree.def));
407 result = sr;
408 }
410 public void visitNewArray(JCNewArray tree) {
411 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
412 sr.mergeWith(csp(tree.elemtype));
413 sr.mergeWith(csp(tree.dims));
414 sr.mergeWith(csp(tree.elems));
415 result = sr;
416 }
418 public void visitParens(JCParens tree) {
419 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
420 sr.mergeWith(csp(tree.expr));
421 result = sr;
422 }
424 public void visitAssign(JCAssign tree) {
425 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
426 sr.mergeWith(csp(tree.lhs));
427 sr.mergeWith(csp(tree.rhs));
428 result = sr;
429 }
431 public void visitAssignop(JCAssignOp tree) {
432 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
433 sr.mergeWith(csp(tree.lhs));
434 sr.mergeWith(csp(tree.rhs));
435 result = sr;
436 }
438 public void visitUnary(JCUnary tree) {
439 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
440 sr.mergeWith(csp(tree.arg));
441 result = sr;
442 }
444 public void visitBinary(JCBinary tree) {
445 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
446 sr.mergeWith(csp(tree.lhs));
447 sr.mergeWith(csp(tree.rhs));
448 result = sr;
449 }
451 public void visitTypeCast(JCTypeCast tree) {
452 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
453 sr.mergeWith(csp(tree.clazz));
454 sr.mergeWith(csp(tree.expr));
455 result = sr;
456 }
458 public void visitTypeTest(JCInstanceOf tree) {
459 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
460 sr.mergeWith(csp(tree.expr));
461 sr.mergeWith(csp(tree.clazz));
462 result = sr;
463 }
465 public void visitIndexed(JCArrayAccess tree) {
466 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
467 sr.mergeWith(csp(tree.indexed));
468 sr.mergeWith(csp(tree.index));
469 result = sr;
470 }
472 public void visitSelect(JCFieldAccess tree) {
473 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
474 sr.mergeWith(csp(tree.selected));
475 result = sr;
476 }
478 public void visitIdent(JCIdent tree) {
479 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
480 result = sr;
481 }
483 public void visitLiteral(JCLiteral tree) {
484 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
485 result = sr;
486 }
488 public void visitTypeIdent(JCPrimitiveTypeTree tree) {
489 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
490 result = sr;
491 }
493 public void visitTypeArray(JCArrayTypeTree tree) {
494 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
495 sr.mergeWith(csp(tree.elemtype));
496 result = sr;
497 }
499 public void visitTypeApply(JCTypeApply tree) {
500 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
501 sr.mergeWith(csp(tree.clazz));
502 sr.mergeWith(csp(tree.arguments));
503 result = sr;
504 }
506 public void visitTypeParameter(JCTypeParameter tree) {
507 SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
508 sr.mergeWith(csp(tree.bounds));
509 result = sr;
510 }
512 public void visitWildcard(JCWildcard tree) {
513 result = null;
514 }
516 public void visitErroneous(JCErroneous tree) {
517 result = null;
518 }
520 public void visitTree(JCTree tree) {
521 Assert.error();
522 }
524 /** The start position of given tree.
525 */
526 public int startPos(JCTree tree) {
527 if (tree == null) return Position.NOPOS;
528 return tree.pos;
529 }
531 /** The end position of given tree, if it has
532 * defined endpos, NOPOS otherwise.
533 */
534 public int endPos(JCTree tree) {
535 if (tree == null) return Position.NOPOS;
536 if (tree.hasTag(JCTree.Tag.BLOCK))
537 return ((JCBlock) tree).endpos;
538 return endPosTable.getEndPos(tree);
539 }
540 }
542 /** This class contains a CharacterRangeTableEntry.
543 */
544 static class CRTEntry {
546 /** A tree or a list of trees to obtain source positions.
547 */
548 Object tree;
550 /** The flags described in the CharacterRangeTable spec.
551 */
552 int flags;
554 /** The starting code position of this entry.
555 */
556 int startPc;
558 /** The ending code position of this entry.
559 */
560 int endPc;
562 /** Constructor */
563 CRTEntry(Object tree, int flags, int startPc, int endPc) {
564 this.tree = tree;
565 this.flags = flags;
566 this.startPc = startPc;
567 this.endPc = endPc;
568 }
569 }
572 /** This class contains source positions
573 * for some tree or list of trees.
574 */
575 static class SourceRange {
577 /** The starting source position.
578 */
579 int startPos;
581 /** The ending source position.
582 */
583 int endPos;
585 /** Constructor */
586 SourceRange() {
587 startPos = Position.NOPOS;
588 endPos = Position.NOPOS;
589 }
591 /** Constructor */
592 SourceRange(int startPos, int endPos) {
593 this.startPos = startPos;
594 this.endPos = endPos;
595 }
597 /** Compare the starting and the ending positions
598 * of the source range and combines them assigning
599 * the widest range to this.
600 */
601 SourceRange mergeWith(SourceRange sr) {
602 if (sr == null) return this;
603 if (startPos == Position.NOPOS)
604 startPos = sr.startPos;
605 else if (sr.startPos != Position.NOPOS)
606 startPos = (startPos < sr.startPos ? startPos : sr.startPos);
607 if (endPos == Position.NOPOS)
608 endPos = sr.endPos;
609 else if (sr.endPos != Position.NOPOS)
610 endPos = (endPos > sr.endPos ? endPos : sr.endPos);
611 return this;
612 }
613 }
615 }