CRTable.java revision 2685:7b80aafb5b76
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.tree.*;
31import com.sun.tools.javac.util.*;
32import com.sun.tools.javac.util.List;
33import com.sun.tools.javac.tree.JCTree.*;
34import 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 */
45public class CRTable
46implements CRTFlags {
47
48    private final boolean crtDebug = false;
49
50    /** The list of CRTable entries.
51     */
52    private ListBuffer<CRTEntry> entries = new ListBuffer<>();
53
54    /** The hashtable for source positions.
55     */
56    private Map<Object,SourceRange> positions = new HashMap<>();
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     */
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     */
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     */
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     */
144    public int length() {
145        return entries.length();
146    }
147
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    }
163
164    /** Source file positions in CRT are integers in the format:
165     *  {@literal 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);
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         */
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         */
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         */
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         */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
365        public void visitBreak(JCBreak tree) {
366            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
367            result = sr;
368        }
369
370        public void visitContinue(JCContinue tree) {
371            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
372            result = sr;
373        }
374
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
478        public void visitIdent(JCIdent tree) {
479            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
480            result = sr;
481        }
482
483        public void visitLiteral(JCLiteral tree) {
484            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
485            result = sr;
486        }
487
488        public void visitTypeIdent(JCPrimitiveTypeTree tree) {
489            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
490            result = sr;
491        }
492
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
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
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
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
520        @Override
521        public void visitTypeUnion(JCTypeUnion tree) {
522            SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
523            sr.mergeWith(csp(tree.alternatives));
524            result = sr;
525        }
526
527        public void visitWildcard(JCWildcard tree) {
528            result = null;
529        }
530
531        public void visitErroneous(JCErroneous tree) {
532            result = null;
533        }
534
535        public void visitTree(JCTree tree) {
536            Assert.error();
537        }
538
539        /** The start position of given tree.
540         */
541        public int startPos(JCTree tree) {
542            if (tree == null) return Position.NOPOS;
543            return TreeInfo.getStartPos(tree);
544        }
545
546        /** The end position of given tree, if it has
547         *  defined endpos, NOPOS otherwise.
548         */
549        public int endPos(JCTree tree) {
550            if (tree == null) return Position.NOPOS;
551            return TreeInfo.getEndPos(tree, endPosTable);
552        }
553    }
554
555    /** This class contains a CharacterRangeTableEntry.
556     */
557    static class CRTEntry {
558
559        /** A tree or a list of trees to obtain source positions.
560         */
561        Object tree;
562
563        /** The flags described in the CharacterRangeTable spec.
564         */
565        int flags;
566
567        /** The starting code position of this entry.
568         */
569        int startPc;
570
571        /** The ending code position of this entry.
572         */
573        int endPc;
574
575        /** Constructor */
576        CRTEntry(Object tree, int flags, int startPc, int endPc) {
577            this.tree = tree;
578            this.flags = flags;
579            this.startPc = startPc;
580            this.endPc = endPc;
581        }
582    }
583
584
585    /** This class contains source positions
586     *  for some tree or list of trees.
587     */
588    static class SourceRange {
589
590        /** The starting source position.
591         */
592        int startPos;
593
594        /** The ending source position.
595         */
596        int endPos;
597
598        /** Constructor */
599        SourceRange() {
600            startPos = Position.NOPOS;
601            endPos = Position.NOPOS;
602        }
603
604        /** Constructor */
605        SourceRange(int startPos, int endPos) {
606            this.startPos = startPos;
607            this.endPos = endPos;
608        }
609
610        /** Compare the starting and the ending positions
611         *  of the source range and combines them assigning
612         *  the widest range to this.
613         */
614        SourceRange mergeWith(SourceRange sr) {
615            if (sr == null) return this;
616            if (startPos == Position.NOPOS)
617                startPos = sr.startPos;
618            else if (sr.startPos != Position.NOPOS)
619                startPos = (startPos < sr.startPos ? startPos : sr.startPos);
620            if (endPos == Position.NOPOS)
621                endPos = sr.endPos;
622            else if (sr.endPos != Position.NOPOS)
623                endPos = (endPos > sr.endPos ? endPos : sr.endPos);
624            return this;
625        }
626    }
627
628}
629