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 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  37 
  38 /** This class contains the CharacterRangeTable for some method
  39  *  and the hashtable for mapping trees or lists of trees to their
  40  *  ending positions.
  41  *
  42  *  <p><b>This is NOT part of any supported API.
  43  *  If you write code that depends on this, you do so at your own risk.
  44  *  This code and its internal interfaces are subject to change or
  45  *  deletion without notice.</b>
  46  */
  47 public class CRTable
  48 implements CRTFlags {
  49 
  50     private final boolean crtDebug = false;
  51 
  52     /** The list of CRTable entries.
  53      */
  54     private ListBuffer<CRTEntry> entries = new ListBuffer<>();
  55 
  56     /** The hashtable for source positions.
  57      */
  58     private Map<Object,SourceRange> positions = new HashMap<>();
  59 
  60     /** The object for ending positions stored in the parser.
  61      */
  62     private EndPosTable endPosTable;
  63 
  64     /** The tree of the method this table is intended for.
  65      *  We should traverse this tree to get source ranges.
  66      */
  67     JCTree.JCMethodDecl methodTree;
  68 
  69     /** Constructor
  70      */
  71     public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) {
  72         this.methodTree = tree;
  73         this.endPosTable = endPosTable;
  74     }
  75 
  76     /** Create a new CRTEntry and add it to the entries.
  77      *  @param tree     The tree or the list of trees for which
  78      *                  we are storing the code pointers.
  79      *  @param flags    The set of flags designating type of the entry.
  80      *  @param startPc  The starting code position.
  81      *  @param endPc    The ending code position.
  82      */
  83     public void put(Object tree, int flags, int startPc, int endPc) {
  84         entries.append(new CRTEntry(tree, flags, startPc, endPc));
  85     }
  86 
  87     /** Compute source positions and write CRT to the databuf.
  88      *  @param databuf  The buffer to write bytecodes to.
  89      */
  90     public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) {
  91 
  92         int crtEntries = 0;
  93 
  94         // compute source positions for the method
  95         new SourceComputer().csp(methodTree);
  96 
  97         for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) {
  98 
  99             CRTEntry entry = l.head;
 100 
 101             // eliminate entries that do not produce bytecodes:
 102             // for example, empty blocks and statements
 103             if (entry.startPc == entry.endPc)
 104                 continue;
 105 
 106             SourceRange pos = positions.get(entry.tree);
 107             Assert.checkNonNull(pos, "CRT: tree source positions are undefined");
 108             if ((pos.startPos == Position.NOPOS) || (pos.endPos == Position.NOPOS))
 109                 continue;
 110 
 111             if (crtDebug) {
 112                 System.out.println("Tree: " + entry.tree + ", type:" + getTypes(entry.flags));
 113                 System.out.print("Start: pos = " + pos.startPos + ", pc = " + entry.startPc);
 114             }
 115 
 116             // encode startPos into line/column representation
 117             int startPos = encodePosition(pos.startPos, lineMap, log);
 118             if (startPos == Position.NOPOS)
 119                 continue;
 120 
 121             if (crtDebug) {
 122                 System.out.print("End:   pos = " + pos.endPos + ", pc = " + (entry.endPc - 1));
 123             }
 124 
 125             // encode endPos into line/column representation
 126             int endPos = encodePosition(pos.endPos, lineMap, log);
 127             if (endPos == Position.NOPOS)
 128                 continue;
 129 
 130             // write attribute
 131             databuf.appendChar(entry.startPc);
 132             // 'endPc - 1' because endPc actually points to start of the next command
 133             databuf.appendChar(entry.endPc - 1);
 134             databuf.appendInt(startPos);
 135             databuf.appendInt(endPos);
 136             databuf.appendChar(entry.flags);
 137 
 138             crtEntries++;
 139         }
 140 
 141         return crtEntries;
 142     }
 143 
 144     /** Return the number of the entries.
 145      */
 146     public int length() {
 147         return entries.length();
 148     }
 149 
 150     /** Return string describing flags enabled.
 151      */
 152     private String getTypes(int flags) {
 153         String types = "";
 154         if ((flags & CRT_STATEMENT)       != 0) types += " CRT_STATEMENT";
 155         if ((flags & CRT_BLOCK)           != 0) types += " CRT_BLOCK";
 156         if ((flags & CRT_ASSIGNMENT)      != 0) types += " CRT_ASSIGNMENT";
 157         if ((flags & CRT_FLOW_CONTROLLER) != 0) types += " CRT_FLOW_CONTROLLER";
 158         if ((flags & CRT_FLOW_TARGET)     != 0) types += " CRT_FLOW_TARGET";
 159         if ((flags & CRT_INVOKE)          != 0) types += " CRT_INVOKE";
 160         if ((flags & CRT_CREATE)          != 0) types += " CRT_CREATE";
 161         if ((flags & CRT_BRANCH_TRUE)     != 0) types += " CRT_BRANCH_TRUE";
 162         if ((flags & CRT_BRANCH_FALSE)    != 0) types += " CRT_BRANCH_FALSE";
 163         return types;
 164     }
 165 
 166     /** Source file positions in CRT are integers in the format:
 167      *  {@literal line-number << LINESHIFT + column-number }
 168      */
 169      private int encodePosition(int pos, Position.LineMap lineMap, Log log) {
 170          int line = lineMap.getLineNumber(pos);
 171          int col = lineMap.getColumnNumber(pos);
 172          int new_pos = Position.encodePosition(line, col);
 173          if (crtDebug) {
 174              System.out.println(", line = " + line + ", column = " + col +
 175                                 ", new_pos = " + new_pos);
 176          }
 177          if (new_pos == Position.NOPOS)
 178              log.warning(pos, Warnings.PositionOverflow(line));
 179 
 180         return new_pos;
 181      }
 182 
 183 /* ************************************************************************
 184  * Traversal methods
 185  *************************************************************************/
 186 
 187     /**
 188      *  This class contains methods to compute source positions for trees.
 189      *  Extends Tree.Visitor to traverse the abstract syntax tree.
 190      */
 191     class SourceComputer extends JCTree.Visitor {
 192 
 193         /** The result of the tree traversal methods.
 194          */
 195         SourceRange result;
 196 
 197         /** Visitor method: compute source positions for a single node.
 198          */
 199         public SourceRange csp(JCTree tree) {
 200             if (tree == null) return null;
 201             tree.accept(this);
 202             if (result != null) {
 203                 positions.put(tree, result);
 204             }
 205             return result;
 206         }
 207 
 208         /** Visitor method: compute source positions for a list of nodes.
 209          */
 210         public SourceRange csp(List<? extends JCTree> trees) {
 211             if ((trees == null) || !(trees.nonEmpty())) return null;
 212             SourceRange list_sr = new SourceRange();
 213             for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
 214                 list_sr.mergeWith(csp(l.head));
 215             }
 216             positions.put(trees, list_sr);
 217             return list_sr;
 218         }
 219 
 220         /**  Visitor method: compute source positions for
 221          *    a list of case blocks of switch statements.
 222          */
 223         public SourceRange cspCases(List<JCCase> trees) {
 224             if ((trees == null) || !(trees.nonEmpty())) return null;
 225             SourceRange list_sr = new SourceRange();
 226             for (List<JCCase> l = trees; l.nonEmpty(); l = l.tail) {
 227                 list_sr.mergeWith(csp(l.head));
 228             }
 229             positions.put(trees, list_sr);
 230             return list_sr;
 231         }
 232 
 233         /**  Visitor method: compute source positions for
 234          *   a list of catch clauses in try statements.
 235          */
 236         public SourceRange cspCatchers(List<JCCatch> trees) {
 237             if ((trees == null) || !(trees.nonEmpty())) return null;
 238             SourceRange list_sr = new SourceRange();
 239             for (List<JCCatch> l = trees; l.nonEmpty(); l = l.tail) {
 240                 list_sr.mergeWith(csp(l.head));
 241             }
 242             positions.put(trees, list_sr);
 243             return list_sr;
 244         }
 245 
 246         public void visitMethodDef(JCMethodDecl tree) {
 247             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 248             sr.mergeWith(csp(tree.body));
 249             result = sr;
 250         }
 251 
 252         public void visitVarDef(JCVariableDecl tree) {
 253             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 254             csp(tree.vartype);
 255             sr.mergeWith(csp(tree.init));
 256             result = sr;
 257         }
 258 
 259         public void visitSkip(JCSkip tree) {
 260             // endPos is the same as startPos for the empty statement
 261             SourceRange sr = new SourceRange(startPos(tree), startPos(tree));
 262             result = sr;
 263         }
 264 
 265         public void visitBlock(JCBlock tree) {
 266             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 267             csp(tree.stats);    // doesn't compare because block's ending position is defined
 268             result = sr;
 269         }
 270 
 271         public void visitDoLoop(JCDoWhileLoop tree) {
 272             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 273             sr.mergeWith(csp(tree.body));
 274             sr.mergeWith(csp(tree.cond));
 275             result = sr;
 276         }
 277 
 278         public void visitWhileLoop(JCWhileLoop tree) {
 279             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 280             sr.mergeWith(csp(tree.cond));
 281             sr.mergeWith(csp(tree.body));
 282             result = sr;
 283         }
 284 
 285         public void visitForLoop(JCForLoop tree) {
 286             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 287             sr.mergeWith(csp(tree.init));
 288             sr.mergeWith(csp(tree.cond));
 289             sr.mergeWith(csp(tree.step));
 290             sr.mergeWith(csp(tree.body));
 291             result = sr;
 292         }
 293 
 294         public void visitForeachLoop(JCEnhancedForLoop tree) {
 295             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 296             sr.mergeWith(csp(tree.var));
 297             sr.mergeWith(csp(tree.expr));
 298             sr.mergeWith(csp(tree.body));
 299             result = sr;
 300         }
 301 
 302         public void visitLabelled(JCLabeledStatement tree) {
 303             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 304             sr.mergeWith(csp(tree.body));
 305             result = sr;
 306         }
 307 
 308         public void visitSwitch(JCSwitch tree) {
 309             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 310             sr.mergeWith(csp(tree.selector));
 311             sr.mergeWith(cspCases(tree.cases));
 312             result = sr;
 313         }
 314 
 315         @Override
 316         public void visitSwitchExpression(JCSwitchExpression tree) {
 317             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 318             sr.mergeWith(csp(tree.selector));
 319             sr.mergeWith(cspCases(tree.cases));
 320             result = sr;
 321         }
 322 
 323         public void visitCase(JCCase tree) {
 324             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 325             sr.mergeWith(csp(tree.pats));
 326             sr.mergeWith(csp(tree.stats));
 327             result = sr;
 328         }
 329 
 330         public void visitSynchronized(JCSynchronized tree) {
 331             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 332             sr.mergeWith(csp(tree.lock));
 333             sr.mergeWith(csp(tree.body));
 334             result = sr;
 335         }
 336 
 337         public void visitTry(JCTry tree) {
 338             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 339             sr.mergeWith(csp(tree.resources));
 340             sr.mergeWith(csp(tree.body));
 341             sr.mergeWith(cspCatchers(tree.catchers));
 342             sr.mergeWith(csp(tree.finalizer));
 343             result = sr;
 344         }
 345 
 346         public void visitCatch(JCCatch tree) {
 347             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 348             sr.mergeWith(csp(tree.param));
 349             sr.mergeWith(csp(tree.body));
 350             result = sr;
 351         }
 352 
 353         public void visitConditional(JCConditional tree) {
 354             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 355             sr.mergeWith(csp(tree.cond));
 356             sr.mergeWith(csp(tree.truepart));
 357             sr.mergeWith(csp(tree.falsepart));
 358             result = sr;
 359         }
 360 
 361         public void visitIf(JCIf tree) {
 362             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 363             sr.mergeWith(csp(tree.cond));
 364             sr.mergeWith(csp(tree.thenpart));
 365             sr.mergeWith(csp(tree.elsepart));
 366             result = sr;
 367         }
 368 
 369         public void visitExec(JCExpressionStatement tree) {
 370             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 371             sr.mergeWith(csp(tree.expr));
 372             result = sr;
 373         }
 374 
 375         public void visitBreak(JCBreak tree) {
 376             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 377             result = sr;
 378         }
 379 
 380         public void visitYield(JCYield tree) {
 381             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 382             result = sr;
 383         }
 384 
 385         public void visitContinue(JCContinue tree) {
 386             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 387             result = sr;
 388         }
 389 
 390         public void visitReturn(JCReturn tree) {
 391             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 392             sr.mergeWith(csp(tree.expr));
 393             result = sr;
 394         }
 395 
 396         public void visitThrow(JCThrow tree) {
 397             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 398             sr.mergeWith(csp(tree.expr));
 399             result = sr;
 400         }
 401 
 402         public void visitAssert(JCAssert tree) {
 403             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 404             sr.mergeWith(csp(tree.cond));
 405             sr.mergeWith(csp(tree.detail));
 406             result = sr;
 407         }
 408 
 409         public void visitApply(JCMethodInvocation tree) {
 410             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 411             sr.mergeWith(csp(tree.meth));
 412             sr.mergeWith(csp(tree.args));
 413             result = sr;
 414         }
 415 
 416         public void visitNewClass(JCNewClass tree) {
 417             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 418             sr.mergeWith(csp(tree.encl));
 419             sr.mergeWith(csp(tree.clazz));
 420             sr.mergeWith(csp(tree.args));
 421             sr.mergeWith(csp(tree.def));
 422             result = sr;
 423         }
 424 
 425         public void visitNewArray(JCNewArray tree) {
 426             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 427             sr.mergeWith(csp(tree.elemtype));
 428             sr.mergeWith(csp(tree.dims));
 429             sr.mergeWith(csp(tree.elems));
 430             result = sr;
 431         }
 432 
 433         public void visitParens(JCParens tree) {
 434             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 435             sr.mergeWith(csp(tree.expr));
 436             result = sr;
 437         }
 438 
 439         public void visitAssign(JCAssign tree) {
 440             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 441             sr.mergeWith(csp(tree.lhs));
 442             sr.mergeWith(csp(tree.rhs));
 443             result = sr;
 444         }
 445 
 446         public void visitAssignop(JCAssignOp tree) {
 447             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 448             sr.mergeWith(csp(tree.lhs));
 449             sr.mergeWith(csp(tree.rhs));
 450             result = sr;
 451         }
 452 
 453         public void visitUnary(JCUnary tree) {
 454             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 455             sr.mergeWith(csp(tree.arg));
 456             result = sr;
 457         }
 458 
 459         public void visitBinary(JCBinary tree) {
 460             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 461             sr.mergeWith(csp(tree.lhs));
 462             sr.mergeWith(csp(tree.rhs));
 463             result = sr;
 464         }
 465 
 466         public void visitTypeCast(JCTypeCast tree) {
 467             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 468             sr.mergeWith(csp(tree.clazz));
 469             sr.mergeWith(csp(tree.expr));
 470             result = sr;
 471         }
 472 
 473         public void visitTypeTest(JCInstanceOf tree) {
 474             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 475             sr.mergeWith(csp(tree.expr));
 476             sr.mergeWith(csp(tree.pattern));
 477             result = sr;
 478         }
 479 
 480         public void visitIndexed(JCArrayAccess tree) {
 481             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 482             sr.mergeWith(csp(tree.indexed));
 483             sr.mergeWith(csp(tree.index));
 484             result = sr;
 485         }
 486 
 487         public void visitSelect(JCFieldAccess tree) {
 488             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 489             sr.mergeWith(csp(tree.selected));
 490             result = sr;
 491         }
 492 
 493         public void visitIdent(JCIdent tree) {
 494             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 495             result = sr;
 496         }
 497 
 498         public void visitLiteral(JCLiteral tree) {
 499             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 500             result = sr;
 501         }
 502 
 503         public void visitTypeIdent(JCPrimitiveTypeTree tree) {
 504             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 505             result = sr;
 506         }
 507 
 508         public void visitTypeArray(JCArrayTypeTree tree) {
 509             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 510             sr.mergeWith(csp(tree.elemtype));
 511             result = sr;
 512         }
 513 
 514         public void visitTypeApply(JCTypeApply tree) {
 515             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 516             sr.mergeWith(csp(tree.clazz));
 517             sr.mergeWith(csp(tree.arguments));
 518             result = sr;
 519         }
 520 
 521         @Override
 522         public void visitLetExpr(LetExpr tree) {
 523             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 524             sr.mergeWith(csp(tree.defs));
 525             sr.mergeWith(csp(tree.expr));
 526             result = sr;
 527         }
 528 
 529         public void visitTypeParameter(JCTypeParameter tree) {
 530             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 531             sr.mergeWith(csp(tree.bounds));
 532             result = sr;
 533         }
 534 
 535         @Override
 536         public void visitTypeUnion(JCTypeUnion tree) {
 537             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
 538             sr.mergeWith(csp(tree.alternatives));
 539             result = sr;
 540         }
 541 
 542         public void visitWildcard(JCWildcard tree) {
 543             result = null;
 544         }
 545 
 546         public void visitErroneous(JCErroneous tree) {
 547             result = null;
 548         }
 549 
 550         public void visitTree(JCTree tree) {
 551             Assert.error();
 552         }
 553 
 554         /** The start position of given tree.
 555          */
 556         public int startPos(JCTree tree) {
 557             if (tree == null) return Position.NOPOS;
 558             return TreeInfo.getStartPos(tree);
 559         }
 560 
 561         /** The end position of given tree, if it has
 562          *  defined endpos, NOPOS otherwise.
 563          */
 564         public int endPos(JCTree tree) {
 565             if (tree == null) return Position.NOPOS;
 566             return TreeInfo.getEndPos(tree, endPosTable);
 567         }
 568     }
 569 
 570     /** This class contains a CharacterRangeTableEntry.
 571      */
 572     static class CRTEntry {
 573 
 574         /** A tree or a list of trees to obtain source positions.
 575          */
 576         Object tree;
 577 
 578         /** The flags described in the CharacterRangeTable spec.
 579          */
 580         int flags;
 581 
 582         /** The starting code position of this entry.
 583          */
 584         int startPc;
 585 
 586         /** The ending code position of this entry.
 587          */
 588         int endPc;
 589 
 590         /** Constructor */
 591         CRTEntry(Object tree, int flags, int startPc, int endPc) {
 592             this.tree = tree;
 593             this.flags = flags;
 594             this.startPc = startPc;
 595             this.endPc = endPc;
 596         }
 597     }
 598 
 599 
 600     /** This class contains source positions
 601      *  for some tree or list of trees.
 602      */
 603     static class SourceRange {
 604 
 605         /** The starting source position.
 606          */
 607         int startPos;
 608 
 609         /** The ending source position.
 610          */
 611         int endPos;
 612 
 613         /** Constructor */
 614         SourceRange() {
 615             startPos = Position.NOPOS;
 616             endPos = Position.NOPOS;
 617         }
 618 
 619         /** Constructor */
 620         SourceRange(int startPos, int endPos) {
 621             this.startPos = startPos;
 622             this.endPos = endPos;
 623         }
 624 
 625         /** Compare the starting and the ending positions
 626          *  of the source range and combines them assigning
 627          *  the widest range to this.
 628          */
 629         SourceRange mergeWith(SourceRange sr) {
 630             if (sr == null) return this;
 631             if (startPos == Position.NOPOS)
 632                 startPos = sr.startPos;
 633             else if (sr.startPos != Position.NOPOS)
 634                 startPos = (startPos < sr.startPos ? startPos : sr.startPos);
 635             if (endPos == Position.NOPOS)
 636                 endPos = sr.endPos;
 637             else if (sr.endPos != Position.NOPOS)
 638                 endPos = (endPos > sr.endPos ? endPos : sr.endPos);
 639             return this;
 640         }
 641     }
 642 
 643 }