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