1 /* 2 * Copyright (c) 2001, 2006, 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 pos != null : "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.body)); 329 sr.mergeWith(cspCatchers(tree.catchers)); 330 sr.mergeWith(csp(tree.finalizer)); 331 result = sr; 332 } 333 334 public void visitCatch(JCCatch tree) { 335 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 336 sr.mergeWith(csp(tree.param)); 337 sr.mergeWith(csp(tree.body)); 338 result = sr; 339 } 340 341 public void visitConditional(JCConditional tree) { 342 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 343 sr.mergeWith(csp(tree.cond)); 344 sr.mergeWith(csp(tree.truepart)); 345 sr.mergeWith(csp(tree.falsepart)); 346 result = sr; 347 } 348 349 public void visitIf(JCIf tree) { 350 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 351 sr.mergeWith(csp(tree.cond)); 352 sr.mergeWith(csp(tree.thenpart)); 353 sr.mergeWith(csp(tree.elsepart)); 354 result = sr; 355 } 356 357 public void visitExec(JCExpressionStatement tree) { 358 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 359 sr.mergeWith(csp(tree.expr)); 360 result = sr; 361 } 362 363 public void visitBreak(JCBreak tree) { 364 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 365 result = sr; 366 } 367 368 public void visitContinue(JCContinue tree) { 369 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 370 result = sr; 371 } 372 373 public void visitReturn(JCReturn tree) { 374 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 375 sr.mergeWith(csp(tree.expr)); 376 result = sr; 377 } 378 379 public void visitThrow(JCThrow tree) { 380 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 381 sr.mergeWith(csp(tree.expr)); 382 result = sr; 383 } 384 385 public void visitAssert(JCAssert tree) { 386 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 387 sr.mergeWith(csp(tree.cond)); 388 sr.mergeWith(csp(tree.detail)); 389 result = sr; 390 } 391 392 public void visitApply(JCMethodInvocation tree) { 393 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 394 sr.mergeWith(csp(tree.meth)); 395 sr.mergeWith(csp(tree.args)); 396 result = sr; 397 } 398 399 public void visitNewClass(JCNewClass tree) { 400 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 401 sr.mergeWith(csp(tree.encl)); 402 sr.mergeWith(csp(tree.clazz)); 403 sr.mergeWith(csp(tree.args)); 404 sr.mergeWith(csp(tree.def)); 405 result = sr; 406 } 407 408 public void visitNewArray(JCNewArray tree) { 409 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 410 sr.mergeWith(csp(tree.elemtype)); 411 sr.mergeWith(csp(tree.dims)); 412 sr.mergeWith(csp(tree.elems)); 413 result = sr; 414 } 415 416 public void visitParens(JCParens tree) { 417 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 418 sr.mergeWith(csp(tree.expr)); 419 result = sr; 420 } 421 422 public void visitAssign(JCAssign tree) { 423 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 424 sr.mergeWith(csp(tree.lhs)); 425 sr.mergeWith(csp(tree.rhs)); 426 result = sr; 427 } 428 429 public void visitAssignop(JCAssignOp tree) { 430 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 431 sr.mergeWith(csp(tree.lhs)); 432 sr.mergeWith(csp(tree.rhs)); 433 result = sr; 434 } 435 436 public void visitUnary(JCUnary tree) { 437 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 438 sr.mergeWith(csp(tree.arg)); 439 result = sr; 440 } 441 442 public void visitBinary(JCBinary tree) { 443 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 444 sr.mergeWith(csp(tree.lhs)); 445 sr.mergeWith(csp(tree.rhs)); 446 result = sr; 447 } 448 449 public void visitTypeCast(JCTypeCast tree) { 450 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 451 sr.mergeWith(csp(tree.clazz)); 452 sr.mergeWith(csp(tree.expr)); 453 result = sr; 454 } 455 456 public void visitTypeTest(JCInstanceOf tree) { 457 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 458 sr.mergeWith(csp(tree.expr)); 459 sr.mergeWith(csp(tree.clazz)); 460 result = sr; 461 } 462 463 public void visitIndexed(JCArrayAccess tree) { 464 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 465 sr.mergeWith(csp(tree.indexed)); 466 sr.mergeWith(csp(tree.index)); 467 result = sr; 468 } 469 470 public void visitSelect(JCFieldAccess tree) { 471 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 472 sr.mergeWith(csp(tree.selected)); 473 result = sr; 474 } 475 476 public void visitIdent(JCIdent tree) { 477 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 478 result = sr; 479 } 480 481 public void visitLiteral(JCLiteral tree) { 482 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 483 result = sr; 484 } 485 486 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 487 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 488 result = sr; 489 } 490 491 public void visitTypeArray(JCArrayTypeTree tree) { 492 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 493 sr.mergeWith(csp(tree.elemtype)); 494 result = sr; 495 } 496 497 public void visitTypeApply(JCTypeApply tree) { 498 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 499 sr.mergeWith(csp(tree.clazz)); 500 sr.mergeWith(csp(tree.arguments)); 501 result = sr; 502 } 503 504 public void visitTypeParameter(JCTypeParameter tree) { 505 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 506 sr.mergeWith(csp(tree.bounds)); 507 result = sr; 508 } 509 510 public void visitWildcard(JCWildcard tree) { 511 result = null; 512 } 513 514 public void visitErroneous(JCErroneous tree) { 515 result = null; 516 } 517 518 public void visitTree(JCTree tree) { 519 assert false; 520 } 521 522 /** The start position of given tree. 523 */ 524 public int startPos(JCTree tree) { 525 if (tree == null) return Position.NOPOS; 526 return tree.pos; 527 } 528 529 /** The end position of given tree, if it has 530 * defined endpos, NOPOS otherwise. 531 */ 532 public int endPos(JCTree tree) { 533 if (tree == null) return Position.NOPOS; 534 if (tree.getTag() == JCTree.BLOCK) 535 return ((JCBlock) tree).endpos; 536 Integer endpos = endPositions.get(tree); 537 if (endpos != null) 538 return endpos.intValue(); 539 return Position.NOPOS; 540 } 541 } 542 543 /** This class contains a CharacterRangeTableEntry. 544 */ 545 static class CRTEntry { 546 547 /** A tree or a list of trees to obtain source positions. 548 */ 549 Object tree; 550 551 /** The flags described in the CharacterRangeTable spec. 552 */ 553 int flags; 554 555 /** The starting code position of this entry. 556 */ 557 int startPc; 558 559 /** The ending code position of this entry. 560 */ 561 int endPc; 562 563 /** Constructor */ 564 CRTEntry(Object tree, int flags, int startPc, int endPc) { 565 this.tree = tree; 566 this.flags = flags; 567 this.startPc = startPc; 568 this.endPc = endPc; 569 } 570 } 571 572 573 /** This class contains source positions 574 * for some tree or list of trees. 575 */ 576 static class SourceRange { 577 578 /** The starting source position. 579 */ 580 int startPos; 581 582 /** The ending source position. 583 */ 584 int endPos; 585 586 /** Constructor */ 587 SourceRange() { 588 startPos = Position.NOPOS; 589 endPos = Position.NOPOS; 590 } 591 592 /** Constructor */ 593 SourceRange(int startPos, int endPos) { 594 this.startPos = startPos; 595 this.endPos = endPos; 596 } 597 598 /** Compare the starting and the ending positions 599 * of the source range and combines them assigning 600 * the widest range to this. 601 */ 602 SourceRange mergeWith(SourceRange sr) { 603 if (sr == null) return this; 604 if (startPos == Position.NOPOS) 605 startPos = sr.startPos; 606 else if (sr.startPos != Position.NOPOS) 607 startPos = (startPos < sr.startPos ? startPos : sr.startPos); 608 if (endPos == Position.NOPOS) 609 endPos = sr.endPos; 610 else if (sr.endPos != Position.NOPOS) 611 endPos = (endPos > sr.endPos ? endPos : sr.endPos); 612 return this; 613 } 614 } 615 616 }