1 /*
  2  * Copyright (c) 2001, 2019, 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.resources.CompilerProperties.Warnings;
 31 import com.sun.tools.javac.tree.*;
 32 import com.sun.tools.javac.util.*;
 33 import com.sun.tools.javac.util.List;
 34 import com.sun.tools.javac.tree.JCTree.*;
 35 import 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  */
 46 public class CRTable
 47 implements 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 visitWithField(JCWithField tree) {
285             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
286             sr.mergeWith(csp(tree.field));
287             sr.mergeWith(csp(tree.value));
288             result = sr;
289         }
290 
291         public void visitForLoop(JCForLoop tree) {
292             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
293             sr.mergeWith(csp(tree.init));
294             sr.mergeWith(csp(tree.cond));
295             sr.mergeWith(csp(tree.step));
296             sr.mergeWith(csp(tree.body));
297             result = sr;
298         }
299 
300         public void visitForeachLoop(JCEnhancedForLoop tree) {
301             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
302             sr.mergeWith(csp(tree.var));
303             sr.mergeWith(csp(tree.expr));
304             sr.mergeWith(csp(tree.body));
305             result = sr;
306         }
307 
308         public void visitLabelled(JCLabeledStatement tree) {
309             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
310             sr.mergeWith(csp(tree.body));
311             result = sr;
312         }
313 
314         public void visitSwitch(JCSwitch tree) {
315             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
316             sr.mergeWith(csp(tree.selector));
317             sr.mergeWith(cspCases(tree.cases));
318             result = sr;
319         }
320 
321         @Override
322         public void visitSwitchExpression(JCSwitchExpression tree) {
323             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
324             sr.mergeWith(csp(tree.selector));
325             sr.mergeWith(cspCases(tree.cases));
326             result = sr;
327         }
328 
329         public void visitCase(JCCase tree) {
330             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
331             sr.mergeWith(csp(tree.labels));
332             sr.mergeWith(csp(tree.stats));
333             result = sr;
334         }
335 
336         @Override
337         public void visitDefaultCaseLabel(JCTree.JCDefaultCaseLabel that) {
338             result = null;
339         }
340 
341         public void visitSynchronized(JCSynchronized tree) {
342             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
343             sr.mergeWith(csp(tree.lock));
344             sr.mergeWith(csp(tree.body));
345             result = sr;
346         }
347 
348         public void visitTry(JCTry tree) {
349             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
350             sr.mergeWith(csp(tree.resources));
351             sr.mergeWith(csp(tree.body));
352             sr.mergeWith(cspCatchers(tree.catchers));
353             sr.mergeWith(csp(tree.finalizer));
354             result = sr;
355         }
356 
357         public void visitCatch(JCCatch tree) {
358             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
359             sr.mergeWith(csp(tree.param));
360             sr.mergeWith(csp(tree.body));
361             result = sr;
362         }
363 
364         public void visitConditional(JCConditional tree) {
365             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
366             sr.mergeWith(csp(tree.cond));
367             sr.mergeWith(csp(tree.truepart));
368             sr.mergeWith(csp(tree.falsepart));
369             result = sr;
370         }
371 
372         @Override
373         public void visitDefaultValue(JCDefaultValue tree) {
374             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
375             sr.mergeWith(csp(tree.clazz));
376             result = sr;
377         }
378 
379         public void visitIf(JCIf tree) {
380             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
381             sr.mergeWith(csp(tree.cond));
382             sr.mergeWith(csp(tree.thenpart));
383             sr.mergeWith(csp(tree.elsepart));
384             result = sr;
385         }
386 
387         public void visitExec(JCExpressionStatement tree) {
388             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
389             sr.mergeWith(csp(tree.expr));
390             result = sr;
391         }
392 
393         public void visitBreak(JCBreak tree) {
394             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
395             result = sr;
396         }
397 
398         public void visitYield(JCYield tree) {
399             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
400             sr.mergeWith(csp(tree.value));
401             result = sr;
402         }
403 
404         public void visitContinue(JCContinue tree) {
405             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
406             result = sr;
407         }
408 
409         public void visitReturn(JCReturn tree) {
410             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
411             sr.mergeWith(csp(tree.expr));
412             result = sr;
413         }
414 
415         public void visitThrow(JCThrow tree) {
416             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
417             sr.mergeWith(csp(tree.expr));
418             result = sr;
419         }
420 
421         public void visitAssert(JCAssert tree) {
422             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
423             sr.mergeWith(csp(tree.cond));
424             sr.mergeWith(csp(tree.detail));
425             result = sr;
426         }
427 
428         public void visitApply(JCMethodInvocation tree) {
429             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
430             sr.mergeWith(csp(tree.meth));
431             sr.mergeWith(csp(tree.args));
432             result = sr;
433         }
434 
435         public void visitNewClass(JCNewClass tree) {
436             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
437             sr.mergeWith(csp(tree.encl));
438             sr.mergeWith(csp(tree.clazz));
439             sr.mergeWith(csp(tree.args));
440             sr.mergeWith(csp(tree.def));
441             result = sr;
442         }
443 
444         public void visitNewArray(JCNewArray tree) {
445             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
446             sr.mergeWith(csp(tree.elemtype));
447             sr.mergeWith(csp(tree.dims));
448             sr.mergeWith(csp(tree.elems));
449             result = sr;
450         }
451 
452         public void visitParens(JCParens tree) {
453             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
454             sr.mergeWith(csp(tree.expr));
455             result = sr;
456         }
457 
458         public void visitAssign(JCAssign tree) {
459             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
460             sr.mergeWith(csp(tree.lhs));
461             sr.mergeWith(csp(tree.rhs));
462             result = sr;
463         }
464 
465         public void visitAssignop(JCAssignOp tree) {
466             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
467             sr.mergeWith(csp(tree.lhs));
468             sr.mergeWith(csp(tree.rhs));
469             result = sr;
470         }
471 
472         public void visitUnary(JCUnary tree) {
473             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
474             sr.mergeWith(csp(tree.arg));
475             result = sr;
476         }
477 
478         public void visitBinary(JCBinary tree) {
479             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
480             sr.mergeWith(csp(tree.lhs));
481             sr.mergeWith(csp(tree.rhs));
482             result = sr;
483         }
484 
485         public void visitTypeCast(JCTypeCast tree) {
486             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
487             sr.mergeWith(csp(tree.clazz));
488             sr.mergeWith(csp(tree.expr));
489             result = sr;
490         }
491 
492         public void visitTypeTest(JCInstanceOf tree) {
493             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
494             sr.mergeWith(csp(tree.expr));
495             sr.mergeWith(csp(tree.pattern));
496             result = sr;
497         }
498 
499         public void visitIndexed(JCArrayAccess tree) {
500             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
501             sr.mergeWith(csp(tree.indexed));
502             sr.mergeWith(csp(tree.index));
503             result = sr;
504         }
505 
506         public void visitSelect(JCFieldAccess tree) {
507             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
508             sr.mergeWith(csp(tree.selected));
509             result = sr;
510         }
511 
512         public void visitIdent(JCIdent tree) {
513             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
514             result = sr;
515         }
516 
517         public void visitLiteral(JCLiteral tree) {
518             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
519             result = sr;
520         }
521 
522         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
523             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
524             result = sr;
525         }
526 
527         public void visitTypeArray(JCArrayTypeTree tree) {
528             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
529             sr.mergeWith(csp(tree.elemtype));
530             result = sr;
531         }
532 
533         public void visitTypeApply(JCTypeApply tree) {
534             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
535             sr.mergeWith(csp(tree.clazz));
536             sr.mergeWith(csp(tree.arguments));
537             result = sr;
538         }
539 
540         @Override
541         public void visitLetExpr(LetExpr tree) {
542             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
543             sr.mergeWith(csp(tree.defs));
544             sr.mergeWith(csp(tree.expr));
545             result = sr;
546         }
547 
548         public void visitTypeParameter(JCTypeParameter tree) {
549             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
550             sr.mergeWith(csp(tree.bounds));
551             result = sr;
552         }
553 
554         @Override
555         public void visitTypeUnion(JCTypeUnion tree) {
556             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
557             sr.mergeWith(csp(tree.alternatives));
558             result = sr;
559         }
560 
561         public void visitWildcard(JCWildcard tree) {
562             result = null;
563         }
564 
565         public void visitErroneous(JCErroneous tree) {
566             result = null;
567         }
568 
569         public void visitTree(JCTree tree) {
570             Assert.error();
571         }
572 
573         /** The start position of given tree.
574          */
575         public int startPos(JCTree tree) {
576             if (tree == null) return Position.NOPOS;
577             return TreeInfo.getStartPos(tree);
578         }
579 
580         /** The end position of given tree, if it has
581          *  defined endpos, NOPOS otherwise.
582          */
583         public int endPos(JCTree tree) {
584             if (tree == null) return Position.NOPOS;
585             return TreeInfo.getEndPos(tree, endPosTable);
586         }
587     }
588 
589     /** This class contains a CharacterRangeTableEntry.
590      */
591     static class CRTEntry {
592 
593         /** A tree or a list of trees to obtain source positions.
594          */
595         Object tree;
596 
597         /** The flags described in the CharacterRangeTable spec.
598          */
599         int flags;
600 
601         /** The starting code position of this entry.
602          */
603         int startPc;
604 
605         /** The ending code position of this entry.
606          */
607         int endPc;
608 
609         /** Constructor */
610         CRTEntry(Object tree, int flags, int startPc, int endPc) {
611             this.tree = tree;
612             this.flags = flags;
613             this.startPc = startPc;
614             this.endPc = endPc;
615         }
616     }
617 
618 
619     /** This class contains source positions
620      *  for some tree or list of trees.
621      */
622     static class SourceRange {
623 
624         /** The starting source position.
625          */
626         int startPos;
627 
628         /** The ending source position.
629          */
630         int endPos;
631 
632         /** Constructor */
633         SourceRange() {
634             startPos = Position.NOPOS;
635             endPos = Position.NOPOS;
636         }
637 
638         /** Constructor */
639         SourceRange(int startPos, int endPos) {
640             this.startPos = startPos;
641             this.endPos = endPos;
642         }
643 
644         /** Compare the starting and the ending positions
645          *  of the source range and combines them assigning
646          *  the widest range to this.
647          */
648         SourceRange mergeWith(SourceRange sr) {
649             if (sr == null) return this;
650             if (startPos == Position.NOPOS)
651                 startPos = sr.startPos;
652             else if (sr.startPos != Position.NOPOS)
653                 startPos = (startPos < sr.startPos ? startPos : sr.startPos);
654             if (endPos == Position.NOPOS)
655                 endPos = sr.endPos;
656             else if (sr.endPos != Position.NOPOS)
657                 endPos = (endPos > sr.endPos ? endPos : sr.endPos);
658             return this;
659         }
660     }
661 
662 }