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 }