CRTable.java revision 4202:2bd34895dda2
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
26package com.sun.tools.javac.jvm;
27
28import java.util.*;
29
30import com.sun.tools.javac.resources.CompilerProperties.Warnings;
31import com.sun.tools.javac.tree.*;
32import com.sun.tools.javac.util.*;
33import com.sun.tools.javac.util.List;
34import com.sun.tools.javac.tree.JCTree.*;
35import com.sun.tools.javac.tree.EndPosTable;
36
37/** This class contains the CharacterRangeTable for some method
38 *  and the hashtable for mapping trees or lists of trees to their
39 *  ending positions.
40 *
41 *  <p><b>This is NOT part of any supported API.
42 *  If you write code that depends on this, you do so at your own risk.
43 *  This code and its internal interfaces are subject to change or
44 *  deletion without notice.</b>
45 */
46public class CRTable
47implements CRTFlags {
48
49    private final boolean crtDebug = false;
50
51    /** The list of CRTable entries.
52     */
53    private ListBuffer<CRTEntry> entries = new ListBuffer<>();
54
55    /** The hashtable for source positions.
56     */
57    private Map<Object,SourceRange> positions = new HashMap<>();
58
59    /** The object for ending positions stored in the parser.
60     */
61    private EndPosTable endPosTable;
62
63    /** The tree of the method this table is intended for.
64     *  We should traverse this tree to get source ranges.
65     */
66    JCTree.JCMethodDecl methodTree;
67
68    /** Constructor
69     */
70    public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) {
71        this.methodTree = tree;
72        this.endPosTable = endPosTable;
73    }
74
75    /** Create a new CRTEntry and add it to the entries.
76     *  @param tree     The tree or the list of trees for which
77     *                  we are storing the code pointers.
78     *  @param flags    The set of flags designating type of the entry.
79     *  @param startPc  The starting code position.
80     *  @param endPc    The ending code position.
81     */
82    public void put(Object tree, int flags, int startPc, int endPc) {
83        entries.append(new CRTEntry(tree, flags, startPc, endPc));
84    }
85
86    /** Compute source positions and write CRT to the databuf.
87     *  @param databuf  The buffer to write bytecodes to.
88     */
89    public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) {
90
91        int crtEntries = 0;
92
93        // compute source positions for the method
94        new SourceComputer().csp(methodTree);
95
96        for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
97
98            CRTEntry entry = l.head;
99
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.checkNonNull(pos, "CRT: tree source positions are undefined");
107            if ((pos.startPos == Position.NOPOS) || (pos.endPos == Position.NOPOS))
108                continue;
109
110            if (crtDebug) {
111                System.out.println("Tree: " + entry.tree + ", type:" + getTypes(entry.flags));
112                System.out.print("Start: pos = " + pos.startPos + ", pc = " + entry.startPc);
113            }
114
115            // encode startPos into line/column representation
116            int startPos = encodePosition(pos.startPos, lineMap, log);
117            if (startPos == Position.NOPOS)
118                continue;
119
120            if (crtDebug) {
121                System.out.print("End:   pos = " + pos.endPos + ", pc = " + (entry.endPc - 1));
122            }
123
124            // encode endPos into line/column representation
125            int endPos = encodePosition(pos.endPos, lineMap, log);
126            if (endPos == Position.NOPOS)
127                continue;
128
129            // write attribute
130            databuf.appendChar(entry.startPc);
131            // 'endPc - 1' because endPc actually points to start of the next command
132            databuf.appendChar(entry.endPc - 1);
133            databuf.appendInt(startPos);
134            databuf.appendInt(endPos);
135            databuf.appendChar(entry.flags);
136
137            crtEntries++;
138        }
139
140        return crtEntries;
141    }
142
143    /** Return the number of the entries.
144     */
145    public int length() {
146        return entries.length();
147    }
148
149    /** Return string describing flags enabled.
150     */
151    private String getTypes(int flags) {
152        String types = "";
153        if ((flags & CRT_STATEMENT)       != 0) types += " CRT_STATEMENT";
154        if ((flags & CRT_BLOCK)           != 0) types += " CRT_BLOCK";
155        if ((flags & CRT_ASSIGNMENT)      != 0) types += " CRT_ASSIGNMENT";
156        if ((flags & CRT_FLOW_CONTROLLER) != 0) types += " CRT_FLOW_CONTROLLER";
157        if ((flags & CRT_FLOW_TARGET)     != 0) types += " CRT_FLOW_TARGET";
158        if ((flags & CRT_INVOKE)          != 0) types += " CRT_INVOKE";
159        if ((flags & CRT_CREATE)          != 0) types += " CRT_CREATE";
160        if ((flags & CRT_BRANCH_TRUE)     != 0) types += " CRT_BRANCH_TRUE";
161        if ((flags & CRT_BRANCH_FALSE)    != 0) types += " CRT_BRANCH_FALSE";
162        return types;
163    }
164
165    /** Source file positions in CRT are integers in the format:
166     *  {@literal line-number << LINESHIFT + column-number }
167     */
168     private int encodePosition(int pos, Position.LineMap lineMap, Log log) {
169         int line = lineMap.getLineNumber(pos);
170         int col = lineMap.getColumnNumber(pos);
171         int new_pos = Position.encodePosition(line, col);
172         if (crtDebug) {
173             System.out.println(", line = " + line + ", column = " + col +
174                                ", new_pos = " + new_pos);
175         }
176         if (new_pos == Position.NOPOS)
177             log.warning(pos, Warnings.PositionOverflow(line));
178
179        return new_pos;
180     }
181
182/* ************************************************************************
183 * Traversal methods
184 *************************************************************************/
185
186    /**
187     *  This class contains methods to compute source positions for trees.
188     *  Extends Tree.Visitor to traverse the abstract syntax tree.
189     */
190    class SourceComputer extends JCTree.Visitor {
191
192        /** The result of the tree traversal methods.
193         */
194        SourceRange result;
195
196        /** Visitor method: compute source positions for a single node.
197         */
198        public SourceRange csp(JCTree tree) {
199            if (tree == null) return null;
200            tree.accept(this);
201            if (result != null) {
202                positions.put(tree, result);
203            }
204            return result;
205        }
206
207        /** Visitor method: compute source positions for a list of nodes.
208         */
209        public SourceRange csp(List<? extends JCTree> trees) {
210            if ((trees == null) || !(trees.nonEmpty())) return null;
211            SourceRange list_sr = new SourceRange();
212            for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
213                list_sr.mergeWith(csp(l.head));
214            }
215            positions.put(trees, list_sr);
216            return list_sr;
217        }
218
219        /**  Visitor method: compute source positions for
220         *    a list of case blocks of switch statements.
221         */
222        public SourceRange cspCases(List<JCCase> trees) {
223            if ((trees == null) || !(trees.nonEmpty())) return null;
224            SourceRange list_sr = new SourceRange();
225            for (List<JCCase> l = trees; l.nonEmpty(); l = l.tail) {
226                list_sr.mergeWith(csp(l.head));
227            }
228            positions.put(trees, list_sr);
229            return list_sr;
230        }
231
232        /**  Visitor method: compute source positions for
233         *   a list of catch clauses in try statements.
234         */
235        public SourceRange cspCatchers(List<JCCatch> trees) {
236            if ((trees == null) || !(trees.nonEmpty())) return null;
237            SourceRange list_sr = new SourceRange();
238            for (List<JCCatch> l = trees; l.nonEmpty(); l = l.tail) {
239                list_sr.mergeWith(csp(l.head));
240            }
241            positions.put(trees, list_sr);
242            return list_sr;
243        }
244
245        public void visitMethodDef(JCMethodDecl tree) {
246            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
247            sr.mergeWith(csp(tree.body));
248            result = sr;
249        }
250
251        public void visitVarDef(JCVariableDecl tree) {
252            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
253            csp(tree.vartype);
254            sr.mergeWith(csp(tree.init));
255            result = sr;
256        }
257
258        public void visitSkip(JCSkip tree) {
259            // endPos is the same as startPos for the empty statement
260            SourceRange sr = new SourceRange(startPos(tree), startPos(tree));
261            result = sr;
262        }
263
264        public void visitBlock(JCBlock tree) {
265            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
266            csp(tree.stats);    // doesn't compare because block's ending position is defined
267            result = sr;
268        }
269
270        public void visitDoLoop(JCDoWhileLoop tree) {
271            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
272            sr.mergeWith(csp(tree.body));
273            sr.mergeWith(csp(tree.cond));
274            result = sr;
275        }
276
277        public void visitWhileLoop(JCWhileLoop tree) {
278            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
279            sr.mergeWith(csp(tree.cond));
280            sr.mergeWith(csp(tree.body));
281            result = sr;
282        }
283
284        public void visitForLoop(JCForLoop tree) {
285            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
286            sr.mergeWith(csp(tree.init));
287            sr.mergeWith(csp(tree.cond));
288            sr.mergeWith(csp(tree.step));
289            sr.mergeWith(csp(tree.body));
290            result = sr;
291        }
292
293        public void visitForeachLoop(JCEnhancedForLoop tree) {
294            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
295            sr.mergeWith(csp(tree.var));
296            sr.mergeWith(csp(tree.expr));
297            sr.mergeWith(csp(tree.body));
298            result = sr;
299        }
300
301        public void visitLabelled(JCLabeledStatement tree) {
302            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
303            sr.mergeWith(csp(tree.body));
304            result = sr;
305        }
306
307        public void visitSwitch(JCSwitch tree) {
308            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
309            sr.mergeWith(csp(tree.selector));
310            sr.mergeWith(cspCases(tree.cases));
311            result = sr;
312        }
313
314        public void visitCase(JCCase tree) {
315            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
316            sr.mergeWith(csp(tree.pat));
317            sr.mergeWith(csp(tree.stats));
318            result = sr;
319        }
320
321        public void visitSynchronized(JCSynchronized tree) {
322            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
323            sr.mergeWith(csp(tree.lock));
324            sr.mergeWith(csp(tree.body));
325            result = sr;
326        }
327
328        public void visitTry(JCTry tree) {
329            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
330            sr.mergeWith(csp(tree.resources));
331            sr.mergeWith(csp(tree.body));
332            sr.mergeWith(cspCatchers(tree.catchers));
333            sr.mergeWith(csp(tree.finalizer));
334            result = sr;
335        }
336
337        public void visitCatch(JCCatch tree) {
338            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
339            sr.mergeWith(csp(tree.param));
340            sr.mergeWith(csp(tree.body));
341            result = sr;
342        }
343
344        public void visitConditional(JCConditional tree) {
345            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
346            sr.mergeWith(csp(tree.cond));
347            sr.mergeWith(csp(tree.truepart));
348            sr.mergeWith(csp(tree.falsepart));
349            result = sr;
350        }
351
352        public void visitIf(JCIf tree) {
353            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
354            sr.mergeWith(csp(tree.cond));
355            sr.mergeWith(csp(tree.thenpart));
356            sr.mergeWith(csp(tree.elsepart));
357            result = sr;
358        }
359
360        public void visitExec(JCExpressionStatement tree) {
361            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
362            sr.mergeWith(csp(tree.expr));
363            result = sr;
364        }
365
366        public void visitBreak(JCBreak tree) {
367            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
368            result = sr;
369        }
370
371        public void visitContinue(JCContinue tree) {
372            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
373            result = sr;
374        }
375
376        public void visitReturn(JCReturn tree) {
377            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
378            sr.mergeWith(csp(tree.expr));
379            result = sr;
380        }
381
382        public void visitThrow(JCThrow tree) {
383            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
384            sr.mergeWith(csp(tree.expr));
385            result = sr;
386        }
387
388        public void visitAssert(JCAssert tree) {
389            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
390            sr.mergeWith(csp(tree.cond));
391            sr.mergeWith(csp(tree.detail));
392            result = sr;
393        }
394
395        public void visitApply(JCMethodInvocation tree) {
396            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
397            sr.mergeWith(csp(tree.meth));
398            sr.mergeWith(csp(tree.args));
399            result = sr;
400        }
401
402        public void visitNewClass(JCNewClass tree) {
403            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
404            sr.mergeWith(csp(tree.encl));
405            sr.mergeWith(csp(tree.clazz));
406            sr.mergeWith(csp(tree.args));
407            sr.mergeWith(csp(tree.def));
408            result = sr;
409        }
410
411        public void visitNewArray(JCNewArray tree) {
412            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
413            sr.mergeWith(csp(tree.elemtype));
414            sr.mergeWith(csp(tree.dims));
415            sr.mergeWith(csp(tree.elems));
416            result = sr;
417        }
418
419        public void visitParens(JCParens tree) {
420            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
421            sr.mergeWith(csp(tree.expr));
422            result = sr;
423        }
424
425        public void visitAssign(JCAssign tree) {
426            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
427            sr.mergeWith(csp(tree.lhs));
428            sr.mergeWith(csp(tree.rhs));
429            result = sr;
430        }
431
432        public void visitAssignop(JCAssignOp tree) {
433            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
434            sr.mergeWith(csp(tree.lhs));
435            sr.mergeWith(csp(tree.rhs));
436            result = sr;
437        }
438
439        public void visitUnary(JCUnary tree) {
440            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
441            sr.mergeWith(csp(tree.arg));
442            result = sr;
443        }
444
445        public void visitBinary(JCBinary tree) {
446            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
447            sr.mergeWith(csp(tree.lhs));
448            sr.mergeWith(csp(tree.rhs));
449            result = sr;
450        }
451
452        public void visitTypeCast(JCTypeCast tree) {
453            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
454            sr.mergeWith(csp(tree.clazz));
455            sr.mergeWith(csp(tree.expr));
456            result = sr;
457        }
458
459        public void visitTypeTest(JCInstanceOf tree) {
460            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
461            sr.mergeWith(csp(tree.expr));
462            sr.mergeWith(csp(tree.clazz));
463            result = sr;
464        }
465
466        public void visitIndexed(JCArrayAccess tree) {
467            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
468            sr.mergeWith(csp(tree.indexed));
469            sr.mergeWith(csp(tree.index));
470            result = sr;
471        }
472
473        public void visitSelect(JCFieldAccess tree) {
474            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
475            sr.mergeWith(csp(tree.selected));
476            result = sr;
477        }
478
479        public void visitIdent(JCIdent tree) {
480            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
481            result = sr;
482        }
483
484        public void visitLiteral(JCLiteral tree) {
485            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
486            result = sr;
487        }
488
489        public void visitTypeIdent(JCPrimitiveTypeTree tree) {
490            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
491            result = sr;
492        }
493
494        public void visitTypeArray(JCArrayTypeTree tree) {
495            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
496            sr.mergeWith(csp(tree.elemtype));
497            result = sr;
498        }
499
500        public void visitTypeApply(JCTypeApply tree) {
501            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
502            sr.mergeWith(csp(tree.clazz));
503            sr.mergeWith(csp(tree.arguments));
504            result = sr;
505        }
506
507        @Override
508        public void visitLetExpr(LetExpr tree) {
509            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
510            sr.mergeWith(csp(tree.defs));
511            sr.mergeWith(csp(tree.expr));
512            result = sr;
513        }
514
515        public void visitTypeParameter(JCTypeParameter tree) {
516            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
517            sr.mergeWith(csp(tree.bounds));
518            result = sr;
519        }
520
521        @Override
522        public void visitTypeUnion(JCTypeUnion tree) {
523            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
524            sr.mergeWith(csp(tree.alternatives));
525            result = sr;
526        }
527
528        public void visitWildcard(JCWildcard tree) {
529            result = null;
530        }
531
532        public void visitErroneous(JCErroneous tree) {
533            result = null;
534        }
535
536        public void visitTree(JCTree tree) {
537            Assert.error();
538        }
539
540        /** The start position of given tree.
541         */
542        public int startPos(JCTree tree) {
543            if (tree == null) return Position.NOPOS;
544            return TreeInfo.getStartPos(tree);
545        }
546
547        /** The end position of given tree, if it has
548         *  defined endpos, NOPOS otherwise.
549         */
550        public int endPos(JCTree tree) {
551            if (tree == null) return Position.NOPOS;
552            return TreeInfo.getEndPos(tree, endPosTable);
553        }
554    }
555
556    /** This class contains a CharacterRangeTableEntry.
557     */
558    static class CRTEntry {
559
560        /** A tree or a list of trees to obtain source positions.
561         */
562        Object tree;
563
564        /** The flags described in the CharacterRangeTable spec.
565         */
566        int flags;
567
568        /** The starting code position of this entry.
569         */
570        int startPc;
571
572        /** The ending code position of this entry.
573         */
574        int endPc;
575
576        /** Constructor */
577        CRTEntry(Object tree, int flags, int startPc, int endPc) {
578            this.tree = tree;
579            this.flags = flags;
580            this.startPc = startPc;
581            this.endPc = endPc;
582        }
583    }
584
585
586    /** This class contains source positions
587     *  for some tree or list of trees.
588     */
589    static class SourceRange {
590
591        /** The starting source position.
592         */
593        int startPos;
594
595        /** The ending source position.
596         */
597        int endPos;
598
599        /** Constructor */
600        SourceRange() {
601            startPos = Position.NOPOS;
602            endPos = Position.NOPOS;
603        }
604
605        /** Constructor */
606        SourceRange(int startPos, int endPos) {
607            this.startPos = startPos;
608            this.endPos = endPos;
609        }
610
611        /** Compare the starting and the ending positions
612         *  of the source range and combines them assigning
613         *  the widest range to this.
614         */
615        SourceRange mergeWith(SourceRange sr) {
616            if (sr == null) return this;
617            if (startPos == Position.NOPOS)
618                startPos = sr.startPos;
619            else if (sr.startPos != Position.NOPOS)
620                startPos = (startPos < sr.startPos ? startPos : sr.startPos);
621            if (endPos == Position.NOPOS)
622                endPos = sr.endPos;
623            else if (sr.endPos != Position.NOPOS)
624                endPos = (endPos > sr.endPos ? endPos : sr.endPos);
625            return this;
626        }
627    }
628
629}
630