1 /*
   2  * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import java.util.*;
  29 
  30 import com.sun.tools.javac.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 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.pats));
 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 }