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.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 false; 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 }