1 /*
2  * Copyright (c) 2001, 2012, 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  */
25 
26 package com.sun.tools.javac.jvm;
27 
28 import java.util.*;
29 
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.tree.EndPosTable;
35 
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 {
47 
48     private final boolean crtDebug = false;
49 
50     /** The list of CRTable entries.
51      */
52     private ListBuffer<CRTEntry> entries = new ListBuffer<CRTEntry>();
53 
54     /** The hashtable for source positions.
55      */
56     private Map<Object,SourceRange> positions = new HashMap<Object,SourceRange>();
57 
58     /** The object for ending positions stored in the parser.
59      */
60     private EndPosTable endPosTable;
61 
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;
66 
67     /** Constructor
68      */
CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable)69     public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) {
70         this.methodTree = tree;
71         this.endPosTable = endPosTable;
72     }
73 
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      */
put(Object tree, int flags, int startPc, int endPc)81     public void put(Object tree, int flags, int startPc, int endPc) {
82         entries.append(new CRTEntry(tree, flags, startPc, endPc));
83     }
84 
85     /** Compute source positions and write CRT to the databuf.
86      *  @param databuf  The buffer to write bytecodes to.
87      */
writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log)88     public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) {
89 
90         int crtEntries = 0;
91 
92         // compute source positions for the method
93         new SourceComputer().csp(methodTree);
94 
95         for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
96 
97             CRTEntry entry = l.head;
98 
99             // eliminate entries that do not produce bytecodes:
100             // for example, empty blocks and statements
101             if (entry.startPc == entry.endPc)
102                 continue;
103 
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;
108 
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             }
113 
114             // encode startPos into line/column representation
115             int startPos = encodePosition(pos.startPos, lineMap, log);
116             if (startPos == Position.NOPOS)
117                 continue;
118 
119             if (crtDebug) {
120                 System.out.print("End:   pos = " + pos.endPos + ", pc = " + (entry.endPc - 1));
121             }
122 
123             // encode endPos into line/column representation
124             int endPos = encodePosition(pos.endPos, lineMap, log);
125             if (endPos == Position.NOPOS)
126                 continue;
127 
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);
135 
136             crtEntries++;
137         }
138 
139         return crtEntries;
140     }
141 
142     /** Return the number of the entries.
143      */
length()144     public int length() {
145         return entries.length();
146     }
147 
148     /** Return string describing flags enabled.
149      */
getTypes(int flags)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     }
163 
164     /** Source file positions in CRT are integers in the format:
165      *  {@literal line-number << LINESHIFT + column-number }
166      */
encodePosition(int pos, Position.LineMap lineMap, Log log)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);
177 
178         return new_pos;
179      }
180 
181 /* ************************************************************************
182  * Traversal methods
183  *************************************************************************/
184 
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 {
190 
191         /** The result of the tree traversal methods.
192          */
193         SourceRange result;
194 
195         /** Visitor method: compute source positions for a single node.
196          */
csp(JCTree tree)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         }
205 
206         /** Visitor method: compute source positions for a list of nodes.
207          */
csp(List<? extends JCTree> trees)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         }
217 
218         /**  Visitor method: compute source positions for
219          *    a list of case blocks of switch statements.
220          */
cspCases(List<JCCase> trees)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         }
230 
231         /**  Visitor method: compute source positions for
232          *   a list of catch clauses in try statements.
233          */
cspCatchers(List<JCCatch> trees)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         }
243 
visitMethodDef(JCMethodDecl tree)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         }
249 
visitVarDef(JCVariableDecl tree)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         }
256 
visitSkip(JCSkip tree)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         }
262 
visitBlock(JCBlock tree)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         }
268 
visitDoLoop(JCDoWhileLoop tree)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         }
275 
visitWhileLoop(JCWhileLoop tree)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         }
282 
visitForLoop(JCForLoop tree)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         }
291 
visitForeachLoop(JCEnhancedForLoop tree)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         }
299 
visitLabelled(JCLabeledStatement tree)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         }
305 
visitSwitch(JCSwitch tree)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         }
312 
visitCase(JCCase tree)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         }
319 
visitSynchronized(JCSynchronized tree)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         }
326 
visitTry(JCTry tree)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         }
335 
visitCatch(JCCatch tree)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         }
342 
visitConditional(JCConditional tree)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         }
350 
visitIf(JCIf tree)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         }
358 
visitExec(JCExpressionStatement tree)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         }
364 
visitBreak(JCBreak tree)365         public void visitBreak(JCBreak tree) {
366             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
367             result = sr;
368         }
369 
visitContinue(JCContinue tree)370         public void visitContinue(JCContinue tree) {
371             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
372             result = sr;
373         }
374 
visitReturn(JCReturn tree)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         }
380 
visitThrow(JCThrow tree)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         }
386 
visitAssert(JCAssert tree)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         }
393 
visitApply(JCMethodInvocation tree)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         }
400 
visitNewClass(JCNewClass tree)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         }
409 
visitNewArray(JCNewArray tree)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         }
417 
visitParens(JCParens tree)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         }
423 
visitAssign(JCAssign tree)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         }
430 
visitAssignop(JCAssignOp tree)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         }
437 
visitUnary(JCUnary tree)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         }
443 
visitBinary(JCBinary tree)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         }
450 
visitTypeCast(JCTypeCast tree)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         }
457 
visitTypeTest(JCInstanceOf tree)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         }
464 
visitIndexed(JCArrayAccess tree)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         }
471 
visitSelect(JCFieldAccess tree)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         }
477 
visitIdent(JCIdent tree)478         public void visitIdent(JCIdent tree) {
479             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
480             result = sr;
481         }
482 
visitLiteral(JCLiteral tree)483         public void visitLiteral(JCLiteral tree) {
484             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
485             result = sr;
486         }
487 
visitTypeIdent(JCPrimitiveTypeTree tree)488         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
489             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
490             result = sr;
491         }
492 
visitTypeArray(JCArrayTypeTree tree)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         }
498 
visitTypeApply(JCTypeApply tree)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         }
505 
506         @Override
visitLetExpr(LetExpr tree)507         public void visitLetExpr(LetExpr tree) {
508             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
509             sr.mergeWith(csp(tree.defs));
510             sr.mergeWith(csp(tree.expr));
511             result = sr;
512         }
513 
visitTypeParameter(JCTypeParameter tree)514         public void visitTypeParameter(JCTypeParameter tree) {
515             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
516             sr.mergeWith(csp(tree.bounds));
517             result = sr;
518         }
519 
visitWildcard(JCWildcard tree)520         public void visitWildcard(JCWildcard tree) {
521             result = null;
522         }
523 
visitErroneous(JCErroneous tree)524         public void visitErroneous(JCErroneous tree) {
525             result = null;
526         }
527 
visitTree(JCTree tree)528         public void visitTree(JCTree tree) {
529             Assert.error();
530         }
531 
532         /** The start position of given tree.
533          */
startPos(JCTree tree)534         public int startPos(JCTree tree) {
535             if (tree == null) return Position.NOPOS;
536             return TreeInfo.getStartPos(tree);
537         }
538 
539         /** The end position of given tree, if it has
540          *  defined endpos, NOPOS otherwise.
541          */
endPos(JCTree tree)542         public int endPos(JCTree tree) {
543             if (tree == null) return Position.NOPOS;
544             return TreeInfo.getEndPos(tree, endPosTable);
545         }
546     }
547 
548     /** This class contains a CharacterRangeTableEntry.
549      */
550     static class CRTEntry {
551 
552         /** A tree or a list of trees to obtain source positions.
553          */
554         Object tree;
555 
556         /** The flags described in the CharacterRangeTable spec.
557          */
558         int flags;
559 
560         /** The starting code position of this entry.
561          */
562         int startPc;
563 
564         /** The ending code position of this entry.
565          */
566         int endPc;
567 
568         /** Constructor */
CRTEntry(Object tree, int flags, int startPc, int endPc)569         CRTEntry(Object tree, int flags, int startPc, int endPc) {
570             this.tree = tree;
571             this.flags = flags;
572             this.startPc = startPc;
573             this.endPc = endPc;
574         }
575     }
576 
577 
578     /** This class contains source positions
579      *  for some tree or list of trees.
580      */
581     static class SourceRange {
582 
583         /** The starting source position.
584          */
585         int startPos;
586 
587         /** The ending source position.
588          */
589         int endPos;
590 
591         /** Constructor */
SourceRange()592         SourceRange() {
593             startPos = Position.NOPOS;
594             endPos = Position.NOPOS;
595         }
596 
597         /** Constructor */
SourceRange(int startPos, int endPos)598         SourceRange(int startPos, int endPos) {
599             this.startPos = startPos;
600             this.endPos = endPos;
601         }
602 
603         /** Compare the starting and the ending positions
604          *  of the source range and combines them assigning
605          *  the widest range to this.
606          */
mergeWith(SourceRange sr)607         SourceRange mergeWith(SourceRange sr) {
608             if (sr == null) return this;
609             if (startPos == Position.NOPOS)
610                 startPos = sr.startPos;
611             else if (sr.startPos != Position.NOPOS)
612                 startPos = (startPos < sr.startPos ? startPos : sr.startPos);
613             if (endPos == Position.NOPOS)
614                 endPos = sr.endPos;
615             else if (sr.endPos != Position.NOPOS)
616                 endPos = (endPos > sr.endPos ? endPos : sr.endPos);
617             return this;
618         }
619     }
620 
621 }
622