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