CRTable.java revision 4202:2bd34895dda2
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 26package com.sun.tools.javac.jvm; 27 28import java.util.*; 29 30import com.sun.tools.javac.resources.CompilerProperties.Warnings; 31import com.sun.tools.javac.tree.*; 32import com.sun.tools.javac.util.*; 33import com.sun.tools.javac.util.List; 34import com.sun.tools.javac.tree.JCTree.*; 35import 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 */ 46public class CRTable 47implements 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 visitForLoop(JCForLoop tree) { 285 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 286 sr.mergeWith(csp(tree.init)); 287 sr.mergeWith(csp(tree.cond)); 288 sr.mergeWith(csp(tree.step)); 289 sr.mergeWith(csp(tree.body)); 290 result = sr; 291 } 292 293 public void visitForeachLoop(JCEnhancedForLoop tree) { 294 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 295 sr.mergeWith(csp(tree.var)); 296 sr.mergeWith(csp(tree.expr)); 297 sr.mergeWith(csp(tree.body)); 298 result = sr; 299 } 300 301 public void visitLabelled(JCLabeledStatement tree) { 302 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 303 sr.mergeWith(csp(tree.body)); 304 result = sr; 305 } 306 307 public void visitSwitch(JCSwitch tree) { 308 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 309 sr.mergeWith(csp(tree.selector)); 310 sr.mergeWith(cspCases(tree.cases)); 311 result = sr; 312 } 313 314 public void visitCase(JCCase tree) { 315 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 316 sr.mergeWith(csp(tree.pat)); 317 sr.mergeWith(csp(tree.stats)); 318 result = sr; 319 } 320 321 public void visitSynchronized(JCSynchronized tree) { 322 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 323 sr.mergeWith(csp(tree.lock)); 324 sr.mergeWith(csp(tree.body)); 325 result = sr; 326 } 327 328 public void visitTry(JCTry tree) { 329 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 330 sr.mergeWith(csp(tree.resources)); 331 sr.mergeWith(csp(tree.body)); 332 sr.mergeWith(cspCatchers(tree.catchers)); 333 sr.mergeWith(csp(tree.finalizer)); 334 result = sr; 335 } 336 337 public void visitCatch(JCCatch tree) { 338 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 339 sr.mergeWith(csp(tree.param)); 340 sr.mergeWith(csp(tree.body)); 341 result = sr; 342 } 343 344 public void visitConditional(JCConditional tree) { 345 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 346 sr.mergeWith(csp(tree.cond)); 347 sr.mergeWith(csp(tree.truepart)); 348 sr.mergeWith(csp(tree.falsepart)); 349 result = sr; 350 } 351 352 public void visitIf(JCIf tree) { 353 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 354 sr.mergeWith(csp(tree.cond)); 355 sr.mergeWith(csp(tree.thenpart)); 356 sr.mergeWith(csp(tree.elsepart)); 357 result = sr; 358 } 359 360 public void visitExec(JCExpressionStatement tree) { 361 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 362 sr.mergeWith(csp(tree.expr)); 363 result = sr; 364 } 365 366 public void visitBreak(JCBreak tree) { 367 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 368 result = sr; 369 } 370 371 public void visitContinue(JCContinue tree) { 372 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 373 result = sr; 374 } 375 376 public void visitReturn(JCReturn tree) { 377 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 378 sr.mergeWith(csp(tree.expr)); 379 result = sr; 380 } 381 382 public void visitThrow(JCThrow tree) { 383 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 384 sr.mergeWith(csp(tree.expr)); 385 result = sr; 386 } 387 388 public void visitAssert(JCAssert tree) { 389 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 390 sr.mergeWith(csp(tree.cond)); 391 sr.mergeWith(csp(tree.detail)); 392 result = sr; 393 } 394 395 public void visitApply(JCMethodInvocation tree) { 396 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 397 sr.mergeWith(csp(tree.meth)); 398 sr.mergeWith(csp(tree.args)); 399 result = sr; 400 } 401 402 public void visitNewClass(JCNewClass tree) { 403 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 404 sr.mergeWith(csp(tree.encl)); 405 sr.mergeWith(csp(tree.clazz)); 406 sr.mergeWith(csp(tree.args)); 407 sr.mergeWith(csp(tree.def)); 408 result = sr; 409 } 410 411 public void visitNewArray(JCNewArray tree) { 412 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 413 sr.mergeWith(csp(tree.elemtype)); 414 sr.mergeWith(csp(tree.dims)); 415 sr.mergeWith(csp(tree.elems)); 416 result = sr; 417 } 418 419 public void visitParens(JCParens tree) { 420 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 421 sr.mergeWith(csp(tree.expr)); 422 result = sr; 423 } 424 425 public void visitAssign(JCAssign tree) { 426 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 427 sr.mergeWith(csp(tree.lhs)); 428 sr.mergeWith(csp(tree.rhs)); 429 result = sr; 430 } 431 432 public void visitAssignop(JCAssignOp tree) { 433 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 434 sr.mergeWith(csp(tree.lhs)); 435 sr.mergeWith(csp(tree.rhs)); 436 result = sr; 437 } 438 439 public void visitUnary(JCUnary tree) { 440 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 441 sr.mergeWith(csp(tree.arg)); 442 result = sr; 443 } 444 445 public void visitBinary(JCBinary tree) { 446 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 447 sr.mergeWith(csp(tree.lhs)); 448 sr.mergeWith(csp(tree.rhs)); 449 result = sr; 450 } 451 452 public void visitTypeCast(JCTypeCast tree) { 453 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 454 sr.mergeWith(csp(tree.clazz)); 455 sr.mergeWith(csp(tree.expr)); 456 result = sr; 457 } 458 459 public void visitTypeTest(JCInstanceOf tree) { 460 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 461 sr.mergeWith(csp(tree.expr)); 462 sr.mergeWith(csp(tree.clazz)); 463 result = sr; 464 } 465 466 public void visitIndexed(JCArrayAccess tree) { 467 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 468 sr.mergeWith(csp(tree.indexed)); 469 sr.mergeWith(csp(tree.index)); 470 result = sr; 471 } 472 473 public void visitSelect(JCFieldAccess tree) { 474 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 475 sr.mergeWith(csp(tree.selected)); 476 result = sr; 477 } 478 479 public void visitIdent(JCIdent tree) { 480 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 481 result = sr; 482 } 483 484 public void visitLiteral(JCLiteral tree) { 485 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 486 result = sr; 487 } 488 489 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 490 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 491 result = sr; 492 } 493 494 public void visitTypeArray(JCArrayTypeTree tree) { 495 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 496 sr.mergeWith(csp(tree.elemtype)); 497 result = sr; 498 } 499 500 public void visitTypeApply(JCTypeApply tree) { 501 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 502 sr.mergeWith(csp(tree.clazz)); 503 sr.mergeWith(csp(tree.arguments)); 504 result = sr; 505 } 506 507 @Override 508 public void visitLetExpr(LetExpr tree) { 509 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 510 sr.mergeWith(csp(tree.defs)); 511 sr.mergeWith(csp(tree.expr)); 512 result = sr; 513 } 514 515 public void visitTypeParameter(JCTypeParameter tree) { 516 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 517 sr.mergeWith(csp(tree.bounds)); 518 result = sr; 519 } 520 521 @Override 522 public void visitTypeUnion(JCTypeUnion tree) { 523 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 524 sr.mergeWith(csp(tree.alternatives)); 525 result = sr; 526 } 527 528 public void visitWildcard(JCWildcard tree) { 529 result = null; 530 } 531 532 public void visitErroneous(JCErroneous tree) { 533 result = null; 534 } 535 536 public void visitTree(JCTree tree) { 537 Assert.error(); 538 } 539 540 /** The start position of given tree. 541 */ 542 public int startPos(JCTree tree) { 543 if (tree == null) return Position.NOPOS; 544 return TreeInfo.getStartPos(tree); 545 } 546 547 /** The end position of given tree, if it has 548 * defined endpos, NOPOS otherwise. 549 */ 550 public int endPos(JCTree tree) { 551 if (tree == null) return Position.NOPOS; 552 return TreeInfo.getEndPos(tree, endPosTable); 553 } 554 } 555 556 /** This class contains a CharacterRangeTableEntry. 557 */ 558 static class CRTEntry { 559 560 /** A tree or a list of trees to obtain source positions. 561 */ 562 Object tree; 563 564 /** The flags described in the CharacterRangeTable spec. 565 */ 566 int flags; 567 568 /** The starting code position of this entry. 569 */ 570 int startPc; 571 572 /** The ending code position of this entry. 573 */ 574 int endPc; 575 576 /** Constructor */ 577 CRTEntry(Object tree, int flags, int startPc, int endPc) { 578 this.tree = tree; 579 this.flags = flags; 580 this.startPc = startPc; 581 this.endPc = endPc; 582 } 583 } 584 585 586 /** This class contains source positions 587 * for some tree or list of trees. 588 */ 589 static class SourceRange { 590 591 /** The starting source position. 592 */ 593 int startPos; 594 595 /** The ending source position. 596 */ 597 int endPos; 598 599 /** Constructor */ 600 SourceRange() { 601 startPos = Position.NOPOS; 602 endPos = Position.NOPOS; 603 } 604 605 /** Constructor */ 606 SourceRange(int startPos, int endPos) { 607 this.startPos = startPos; 608 this.endPos = endPos; 609 } 610 611 /** Compare the starting and the ending positions 612 * of the source range and combines them assigning 613 * the widest range to this. 614 */ 615 SourceRange mergeWith(SourceRange sr) { 616 if (sr == null) return this; 617 if (startPos == Position.NOPOS) 618 startPos = sr.startPos; 619 else if (sr.startPos != Position.NOPOS) 620 startPos = (startPos < sr.startPos ? startPos : sr.startPos); 621 if (endPos == Position.NOPOS) 622 endPos = sr.endPos; 623 else if (sr.endPos != Position.NOPOS) 624 endPos = (endPos > sr.endPos ? endPos : sr.endPos); 625 return this; 626 } 627 } 628 629} 630