1 /*
   2  * Copyright (c) 2001, 2011, 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.tree.*;
  31 import com.sun.tools.javac.util.*;
  32 import com.sun.tools.javac.util.List;
  33 import com.sun.tools.javac.tree.JCTree.*;
  34 
  35 /** This class contains the CharacterRangeTable for some method
  36  *  and the hashtable for mapping trees or lists of trees to their
  37  *  ending positions.
  38  *
  39  *  <p><b>This is NOT part of any supported API.
  40  *  If you write code that depends on this, you do so at your own risk.
  41  *  This code and its internal interfaces are subject to change or
  42  *  deletion without notice.</b>
  43  */
  44 public class CRTable
  45 implements CRTFlags {
  46 
  47     private final boolean crtDebug = false;
  48 
  49     /** The list of CRTable entries.
  50      */
  51     private ListBuffer<CRTEntry> entries = new ListBuffer<CRTEntry>();
  52 
  53     /** The hashtable for source positions.
  54      */
  55     private Map<Object,SourceRange> positions = new HashMap<Object,SourceRange>();
  56 
  57     /** The hashtable for ending positions stored in the parser.
  58      */
  59     private Map<JCTree, Integer> endPositions;
  60 
  61     /** The tree of the method this table is intended for.
  62      *  We should traverse this tree to get source ranges.
  63      */
  64     JCTree.JCMethodDecl methodTree;
  65 
  66     /** Constructor
  67      */
  68     public CRTable(JCTree.JCMethodDecl tree, Map<JCTree, Integer> endPositions) {
  69         this.methodTree = tree;
  70         this.endPositions = endPositions;
  71     }
  72 
  73     /** Create a new CRTEntry and add it to the entries.
  74      *  @param tree     The tree or the list of trees for which
  75      *                  we are storing the code pointers.
  76      *  @param flags    The set of flags designating type of the entry.
  77      *  @param startPc  The starting code position.
  78      *  @param endPc    The ending code position.
  79      */
  80     public void put(Object tree, int flags, int startPc, int endPc) {
  81         entries.append(new CRTEntry(tree, flags, startPc, endPc));
  82     }
  83 
  84     /** Compute source positions and write CRT to the databuf.
  85      *  @param databuf  The buffer to write bytecodes to.
  86      */
  87     public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) {
  88 
  89         int crtEntries = 0;
  90 
  91         // compute source positions for the method
  92         new SourceComputer().csp(methodTree);
  93 
  94         for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
  95 
  96             CRTEntry entry = l.head;
  97 
  98             // eliminate entries that do not produce bytecodes:
  99             // for example, empty blocks and statements
 100             if (entry.startPc == entry.endPc)
 101                 continue;
 102 
 103             SourceRange pos = positions.get(entry.tree);
 104             Assert.checkNonNull(pos, "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.resources));
 329             sr.mergeWith(csp(tree.body));
 330             sr.mergeWith(cspCatchers(tree.catchers));
 331             sr.mergeWith(csp(tree.finalizer));
 332             result = sr;
 333         }
 334 
 335         public void visitCatch(JCCatch tree) {
 336             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 337             sr.mergeWith(csp(tree.param));
 338             sr.mergeWith(csp(tree.body));
 339             result = sr;
 340         }
 341 
 342         public void visitConditional(JCConditional tree) {
 343             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 344             sr.mergeWith(csp(tree.cond));
 345             sr.mergeWith(csp(tree.truepart));
 346             sr.mergeWith(csp(tree.falsepart));
 347             result = sr;
 348         }
 349 
 350         public void visitIf(JCIf tree) {
 351             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 352             sr.mergeWith(csp(tree.cond));
 353             sr.mergeWith(csp(tree.thenpart));
 354             sr.mergeWith(csp(tree.elsepart));
 355             result = sr;
 356         }
 357 
 358         public void visitExec(JCExpressionStatement tree) {
 359             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 360             sr.mergeWith(csp(tree.expr));
 361             result = sr;
 362         }
 363 
 364         public void visitBreak(JCBreak tree) {
 365             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 366             result = sr;
 367         }
 368 
 369         public void visitContinue(JCContinue tree) {
 370             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 371             result = sr;
 372         }
 373 
 374         public void visitReturn(JCReturn tree) {
 375             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 376             sr.mergeWith(csp(tree.expr));
 377             result = sr;
 378         }
 379 
 380         public void visitThrow(JCThrow tree) {
 381             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 382             sr.mergeWith(csp(tree.expr));
 383             result = sr;
 384         }
 385 
 386         public void visitAssert(JCAssert tree) {
 387             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 388             sr.mergeWith(csp(tree.cond));
 389             sr.mergeWith(csp(tree.detail));
 390             result = sr;
 391         }
 392 
 393         public void visitApply(JCMethodInvocation tree) {
 394             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 395             sr.mergeWith(csp(tree.meth));
 396             sr.mergeWith(csp(tree.args));
 397             result = sr;
 398         }
 399 
 400         public void visitNewClass(JCNewClass tree) {
 401             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 402             sr.mergeWith(csp(tree.encl));
 403             sr.mergeWith(csp(tree.clazz));
 404             sr.mergeWith(csp(tree.args));
 405             sr.mergeWith(csp(tree.def));
 406             result = sr;
 407         }
 408 
 409         public void visitNewArray(JCNewArray tree) {
 410             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 411             sr.mergeWith(csp(tree.elemtype));
 412             sr.mergeWith(csp(tree.dims));
 413             sr.mergeWith(csp(tree.elems));
 414             result = sr;
 415         }
 416 
 417         public void visitParens(JCParens tree) {
 418             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 419             sr.mergeWith(csp(tree.expr));
 420             result = sr;
 421         }
 422 
 423         public void visitAssign(JCAssign tree) {
 424             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 425             sr.mergeWith(csp(tree.lhs));
 426             sr.mergeWith(csp(tree.rhs));
 427             result = sr;
 428         }
 429 
 430         public void visitAssignop(JCAssignOp tree) {
 431             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 432             sr.mergeWith(csp(tree.lhs));
 433             sr.mergeWith(csp(tree.rhs));
 434             result = sr;
 435         }
 436 
 437         public void visitUnary(JCUnary tree) {
 438             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 439             sr.mergeWith(csp(tree.arg));
 440             result = sr;
 441         }
 442 
 443         public void visitBinary(JCBinary tree) {
 444             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 445             sr.mergeWith(csp(tree.lhs));
 446             sr.mergeWith(csp(tree.rhs));
 447             result = sr;
 448         }
 449 
 450         public void visitTypeCast(JCTypeCast tree) {
 451             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 452             sr.mergeWith(csp(tree.clazz));
 453             sr.mergeWith(csp(tree.expr));
 454             result = sr;
 455         }
 456 
 457         public void visitTypeTest(JCInstanceOf tree) {
 458             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 459             sr.mergeWith(csp(tree.expr));
 460             sr.mergeWith(csp(tree.clazz));
 461             result = sr;
 462         }
 463 
 464         public void visitIndexed(JCArrayAccess tree) {
 465             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 466             sr.mergeWith(csp(tree.indexed));
 467             sr.mergeWith(csp(tree.index));
 468             result = sr;
 469         }
 470 
 471         public void visitSelect(JCFieldAccess tree) {
 472             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 473             sr.mergeWith(csp(tree.selected));
 474             result = sr;
 475         }
 476 
 477         public void visitIdent(JCIdent tree) {
 478             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 479             result = sr;
 480         }
 481 
 482         public void visitLiteral(JCLiteral tree) {
 483             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 484             result = sr;
 485         }
 486 
 487         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
 488             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 489             result = sr;
 490         }
 491 
 492         public void visitTypeArray(JCArrayTypeTree tree) {
 493             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 494             sr.mergeWith(csp(tree.elemtype));
 495             result = sr;
 496         }
 497 
 498         public void visitTypeApply(JCTypeApply tree) {
 499             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 500             sr.mergeWith(csp(tree.clazz));
 501             sr.mergeWith(csp(tree.arguments));
 502             result = sr;
 503         }
 504 
 505         public void visitTypeParameter(JCTypeParameter tree) {
 506             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 507             sr.mergeWith(csp(tree.bounds));
 508             result = sr;
 509         }
 510 
 511         public void visitWildcard(JCWildcard tree) {
 512             result = null;
 513         }
 514 
 515         public void visitErroneous(JCErroneous tree) {
 516             result = null;
 517         }
 518 
 519         public void visitTree(JCTree tree) {
 520             Assert.error();
 521         }
 522 
 523         /** The start position of given tree.
 524          */
 525         public int startPos(JCTree tree) {
 526             if (tree == null) return Position.NOPOS;
 527             return tree.pos;
 528         }
 529 
 530         /** The end position of given tree, if it has
 531          *  defined endpos, NOPOS otherwise.
 532          */
 533         public int endPos(JCTree tree) {
 534             if (tree == null) return Position.NOPOS;
 535             if (tree.getTag() == JCTree.BLOCK)
 536                 return ((JCBlock) tree).endpos;
 537             Integer endpos = endPositions.get(tree);
 538             if (endpos != null)
 539                 return endpos.intValue();
 540             return Position.NOPOS;
 541         }
 542     }
 543 
 544     /** This class contains a CharacterRangeTableEntry.
 545      */
 546     static class CRTEntry {
 547 
 548         /** A tree or a list of trees to obtain source positions.
 549          */
 550         Object tree;
 551 
 552         /** The flags described in the CharacterRangeTable spec.
 553          */
 554         int flags;
 555 
 556         /** The starting code position of this entry.
 557          */
 558         int startPc;
 559 
 560         /** The ending code position of this entry.
 561          */
 562         int endPc;
 563 
 564         /** Constructor */
 565         CRTEntry(Object tree, int flags, int startPc, int endPc) {
 566             this.tree = tree;
 567             this.flags = flags;
 568             this.startPc = startPc;
 569             this.endPc = endPc;
 570         }
 571     }
 572 
 573 
 574     /** This class contains source positions
 575      *  for some tree or list of trees.
 576      */
 577     static class SourceRange {
 578 
 579         /** The starting source position.
 580          */
 581         int startPos;
 582 
 583         /** The ending source position.
 584          */
 585         int endPos;
 586 
 587         /** Constructor */
 588         SourceRange() {
 589             startPos = Position.NOPOS;
 590             endPos = Position.NOPOS;
 591         }
 592 
 593         /** Constructor */
 594         SourceRange(int startPos, int endPos) {
 595             this.startPos = startPos;
 596             this.endPos = endPos;
 597         }
 598 
 599         /** Compare the starting and the ending positions
 600          *  of the source range and combines them assigning
 601          *  the widest range to this.
 602          */
 603         SourceRange mergeWith(SourceRange sr) {
 604             if (sr == null) return this;
 605             if (startPos == Position.NOPOS)
 606                 startPos = sr.startPos;
 607             else if (sr.startPos != Position.NOPOS)
 608                 startPos = (startPos < sr.startPos ? startPos : sr.startPos);
 609             if (endPos == Position.NOPOS)
 610                 endPos = sr.endPos;
 611             else if (sr.endPos != Position.NOPOS)
 612                 endPos = (endPos > sr.endPos ? endPos : sr.endPos);
 613             return this;
 614         }
 615     }
 616 
 617 }