588 589 // Append class definition tree to owner's definitions. 590 odef.defs = odef.defs.prepend(cdef); 591 592 return c; 593 } 594 595 /************************************************************************** 596 * Symbol manipulation utilities 597 *************************************************************************/ 598 599 /** Enter a synthetic symbol in a given scope, but complain if there was already one there. 600 * @param pos Position for error reporting. 601 * @param sym The symbol. 602 * @param s The scope. 603 */ 604 private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) { 605 s.enter(sym); 606 } 607 608 /** Check whether synthetic symbols generated during lowering conflict 609 * with user-defined symbols. 610 * 611 * @param translatedTrees lowered class trees 612 */ 613 void checkConflicts(List<JCTree> translatedTrees) { 614 for (JCTree t : translatedTrees) { 615 t.accept(conflictsChecker); 616 } 617 } 618 619 JCTree.Visitor conflictsChecker = new TreeScanner() { 620 621 TypeSymbol currentClass; 622 623 @Override 624 public void visitMethodDef(JCMethodDecl that) { 625 chk.checkConflicts(that.pos(), that.sym, currentClass); 626 super.visitMethodDef(that); 627 } 1282 make.Call( 1283 make.App( 1284 callee, 1285 make.Idents(md.params.reverse().tail.reverse()))))); 1286 return md; 1287 } 1288 1289 /************************************************************************** 1290 * Free variables proxies and this$n 1291 *************************************************************************/ 1292 1293 /** A scope containing all free variable proxies for currently translated 1294 * class, as well as its this$n symbol (if needed). 1295 * Proxy scopes are nested in the same way classes are. 1296 * Inside a constructor, proxies and any this$n symbol are duplicated 1297 * in an additional innermost scope, where they represent the constructor 1298 * parameters. 1299 */ 1300 Scope proxies; 1301 1302 /** A stack containing the this$n field of the currently translated 1303 * classes (if needed) in innermost first order. 1304 * Inside a constructor, proxies and any this$n symbol are duplicated 1305 * in an additional innermost scope, where they represent the constructor 1306 * parameters. 1307 */ 1308 List<VarSymbol> outerThisStack; 1309 1310 /** The name of a free variable proxy. 1311 */ 1312 Name proxyName(Name name) { 1313 return names.fromString("val" + target.syntheticNameChar() + name); 1314 } 1315 1316 /** Proxy definitions for all free variables in given list, in reverse order. 1317 * @param pos The source code position of the definition. 1318 * @param freevars The free variables. 1319 * @param owner The class in which the definitions go. 1320 */ 1321 List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) { 1383 } 1384 //where 1385 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) { 1386 return access(v, make.at(pos).Ident(v), null, false); 1387 } 1388 1389 /** Construct a tree simulating the expression <C.this>. 1390 * @param pos The source code position to be used for the tree. 1391 * @param c The qualifier class. 1392 */ 1393 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) { 1394 if (currentClass == c) { 1395 // in this case, `this' works fine 1396 return make.at(pos).This(c.erasure(types)); 1397 } else { 1398 // need to go via this$n 1399 return makeOuterThis(pos, c); 1400 } 1401 } 1402 1403 /** Construct a tree that represents the outer instance 1404 * <C.this>. Never pick the current `this'. 1405 * @param pos The source code position to be used for the tree. 1406 * @param c The qualifier class. 1407 */ 1408 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { 1409 List<VarSymbol> ots = outerThisStack; 1410 if (ots.isEmpty()) { 1411 log.error(pos, "no.encl.instance.of.type.in.scope", c); 1412 assert false; 1413 return makeNull(); 1414 } 1415 VarSymbol ot = ots.head; 1416 JCExpression tree = access(make.at(pos).Ident(ot)); 1417 TypeSymbol otc = ot.type.tsym; 1418 while (otc != c) { 1419 do { 1420 ots = ots.tail; 1421 if (ots.isEmpty()) { 1422 log.error(pos, 3388 if (tree.name == names._class) 3389 result = classOf(tree.selected); 3390 else if (tree.name == names._this || tree.name == names._super) 3391 result = makeThis(tree.pos(), tree.selected.type.tsym); 3392 else 3393 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess); 3394 } 3395 3396 public void visitLetExpr(LetExpr tree) { 3397 tree.defs = translateVarDefs(tree.defs); 3398 tree.expr = translate(tree.expr, tree.type); 3399 result = tree; 3400 } 3401 3402 // There ought to be nothing to rewrite here; 3403 // we don't generate code. 3404 public void visitAnnotation(JCAnnotation tree) { 3405 result = tree; 3406 } 3407 3408 /************************************************************************** 3409 * main method 3410 *************************************************************************/ 3411 3412 /** Translate a toplevel class and return a list consisting of 3413 * the translated class and translated versions of all inner classes. 3414 * @param env The attribution environment current at the class definition. 3415 * We need this for resolving some additional symbols. 3416 * @param cdef The tree representing the class definition. 3417 */ 3418 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 3419 ListBuffer<JCTree> translated = null; 3420 try { 3421 attrEnv = env; 3422 this.make = make; 3423 endPositions = env.toplevel.endPositions; 3424 currentClass = null; 3425 currentMethodDef = null; 3426 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; 3427 outermostMemberDef = null; 3428 this.translated = new ListBuffer<JCTree>(); 3429 classdefs = new HashMap<ClassSymbol,JCClassDecl>(); 3430 actualSymbols = new HashMap<Symbol,Symbol>(); 3431 freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>(); 3432 proxies = new Scope(syms.noSymbol); 3433 outerThisStack = List.nil(); 3434 accessNums = new HashMap<Symbol,Integer>(); 3435 accessSyms = new HashMap<Symbol,MethodSymbol[]>(); 3436 accessConstrs = new HashMap<Symbol,MethodSymbol>(); 3437 accessConstrTags = List.nil(); 3438 accessed = new ListBuffer<Symbol>(); 3439 translate(cdef, (JCExpression)null); 3440 for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail) 3441 makeAccessible(l.head); 3442 for (EnumMapping map : enumSwitchMap.values()) 3443 map.translate(); 3444 checkConflicts(this.translated.toList()); 3445 checkAccessConstructorTags(); 3446 translated = this.translated; 3447 } finally { 3448 // note that recursive invocations of this method fail hard 3449 attrEnv = null; 3450 this.make = null; 3451 endPositions = null; 3452 currentClass = null; | 588 589 // Append class definition tree to owner's definitions. 590 odef.defs = odef.defs.prepend(cdef); 591 592 return c; 593 } 594 595 /************************************************************************** 596 * Symbol manipulation utilities 597 *************************************************************************/ 598 599 /** Enter a synthetic symbol in a given scope, but complain if there was already one there. 600 * @param pos Position for error reporting. 601 * @param sym The symbol. 602 * @param s The scope. 603 */ 604 private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) { 605 s.enter(sym); 606 } 607 608 /** Create a fresh synthetic name within a given scope - the unique name is 609 * obtained by appending '$' chars at the end of the name until no match 610 * is found. 611 * 612 * @param name base name 613 * @param s scope in which the name has to be unique 614 * @return fresh synthetic name 615 */ 616 private Name makeSyntheticName(Name name, Scope s) { 617 do { 618 name = name.append( 619 target.syntheticNameChar(), 620 names.empty); 621 } while (lookupSynthetic(name, s) != null); 622 return name; 623 } 624 625 /** Check whether synthetic symbols generated during lowering conflict 626 * with user-defined symbols. 627 * 628 * @param translatedTrees lowered class trees 629 */ 630 void checkConflicts(List<JCTree> translatedTrees) { 631 for (JCTree t : translatedTrees) { 632 t.accept(conflictsChecker); 633 } 634 } 635 636 JCTree.Visitor conflictsChecker = new TreeScanner() { 637 638 TypeSymbol currentClass; 639 640 @Override 641 public void visitMethodDef(JCMethodDecl that) { 642 chk.checkConflicts(that.pos(), that.sym, currentClass); 643 super.visitMethodDef(that); 644 } 1299 make.Call( 1300 make.App( 1301 callee, 1302 make.Idents(md.params.reverse().tail.reverse()))))); 1303 return md; 1304 } 1305 1306 /************************************************************************** 1307 * Free variables proxies and this$n 1308 *************************************************************************/ 1309 1310 /** A scope containing all free variable proxies for currently translated 1311 * class, as well as its this$n symbol (if needed). 1312 * Proxy scopes are nested in the same way classes are. 1313 * Inside a constructor, proxies and any this$n symbol are duplicated 1314 * in an additional innermost scope, where they represent the constructor 1315 * parameters. 1316 */ 1317 Scope proxies; 1318 1319 /** A scope containing all unnamed resource variables/saved exception variables 1320 * for translated ARM blocks 1321 */ 1322 Scope armVars; 1323 1324 /** A stack containing the this$n field of the currently translated 1325 * classes (if needed) in innermost first order. 1326 * Inside a constructor, proxies and any this$n symbol are duplicated 1327 * in an additional innermost scope, where they represent the constructor 1328 * parameters. 1329 */ 1330 List<VarSymbol> outerThisStack; 1331 1332 /** The name of a free variable proxy. 1333 */ 1334 Name proxyName(Name name) { 1335 return names.fromString("val" + target.syntheticNameChar() + name); 1336 } 1337 1338 /** Proxy definitions for all free variables in given list, in reverse order. 1339 * @param pos The source code position of the definition. 1340 * @param freevars The free variables. 1341 * @param owner The class in which the definitions go. 1342 */ 1343 List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) { 1405 } 1406 //where 1407 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) { 1408 return access(v, make.at(pos).Ident(v), null, false); 1409 } 1410 1411 /** Construct a tree simulating the expression <C.this>. 1412 * @param pos The source code position to be used for the tree. 1413 * @param c The qualifier class. 1414 */ 1415 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) { 1416 if (currentClass == c) { 1417 // in this case, `this' works fine 1418 return make.at(pos).This(c.erasure(types)); 1419 } else { 1420 // need to go via this$n 1421 return makeOuterThis(pos, c); 1422 } 1423 } 1424 1425 /** Optionally replace a try statement with an automatic resource management 1426 * (ARM) block. 1427 * @param tree The try statement to inspect. 1428 * @return An ARM block, or the original try block if there are no 1429 * resources to manage. 1430 */ 1431 JCTree makeArmTry(JCTry tree) { 1432 make_at(tree.pos()); 1433 armVars = armVars.dup(); 1434 JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0); 1435 if (tree.catchers.isEmpty() && tree.finalizer == null) 1436 result = translate(armBlock); 1437 else 1438 result = translate(make.Try(armBlock, tree.catchers, tree.finalizer)); 1439 armVars = armVars.leave(); 1440 return result; 1441 } 1442 1443 private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) { 1444 if (resources.isEmpty()) 1445 return block; 1446 1447 // Add resource declaration or expression to block statements 1448 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); 1449 JCTree resource = resources.head; 1450 JCExpression expr = null; 1451 if (resource instanceof JCVariableDecl) { 1452 JCVariableDecl var = (JCVariableDecl) resource; 1453 expr = make.Ident(var.sym).setType(resource.type); 1454 stats.add(var); 1455 } else { 1456 assert resource instanceof JCExpression; 1457 VarSymbol syntheticArmVar = 1458 new VarSymbol(SYNTHETIC | FINAL, 1459 makeSyntheticName(names.fromString("armVar" + 1460 depth), armVars), 1461 (resource.type.tag == TypeTags.BOT) ? 1462 syms.autoCloseableType : resource.type, 1463 currentMethodSym); 1464 armVars.enter(syntheticArmVar); 1465 JCVariableDecl syntheticArmVarDecl = 1466 make.VarDef(syntheticArmVar, (JCExpression)resource); 1467 expr = (JCExpression)make.Ident(syntheticArmVar); 1468 stats.add(syntheticArmVarDecl); 1469 } 1470 1471 // Add primaryException declaration 1472 VarSymbol primaryException = 1473 new VarSymbol(SYNTHETIC, 1474 makeSyntheticName(names.fromString("primaryException" + 1475 depth), armVars), 1476 syms.throwableType, 1477 currentMethodSym); 1478 armVars.enter(primaryException); 1479 JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); 1480 stats.add(primaryExceptionTreeDecl); 1481 1482 // Create catch clause that saves exception and then rethrows it 1483 VarSymbol param = 1484 new VarSymbol(FINAL|SYNTHETIC, 1485 names.fromString("t" + 1486 target.syntheticNameChar()), 1487 syms.throwableType, 1488 currentMethodSym); 1489 JCVariableDecl paramTree = make.VarDef(param, null); 1490 JCStatement assign = make.Assignment(primaryException, make.Ident(param)); 1491 JCStatement rethrowStat = make.Throw(make.Ident(param)); 1492 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat)); 1493 JCCatch catchClause = make.Catch(paramTree, catchBlock); 1494 1495 int oldPos = make.pos; 1496 make.at(TreeInfo.endPos(block)); 1497 JCBlock finallyClause = makeArmFinallyClause(primaryException, expr); 1498 make.at(oldPos); 1499 JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1), 1500 List.<JCCatch>of(catchClause), 1501 finallyClause); 1502 stats.add(outerTry); 1503 return make.Block(0L, stats.toList()); 1504 } 1505 1506 private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) { 1507 // primaryException.addSuppressedException(catchException); 1508 VarSymbol catchException = 1509 new VarSymbol(0, make.paramName(2), 1510 syms.throwableType, 1511 currentMethodSym); 1512 JCStatement addSuppressionStatement = 1513 make.Exec(makeCall(make.Ident(primaryException), 1514 names.fromString("addSuppressedException"), 1515 List.<JCExpression>of(make.Ident(catchException)))); 1516 1517 // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } 1518 JCBlock tryBlock = 1519 make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource))); 1520 JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); 1521 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement)); 1522 List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock)); 1523 JCTry tryTree = make.Try(tryBlock, catchClauses, null); 1524 1525 // if (resource != null) resourceClose; 1526 JCExpression nullCheck = makeBinary(JCTree.NE, 1527 make.Ident(primaryException), 1528 makeNull()); 1529 JCIf closeIfStatement = make.If(nullCheck, 1530 tryTree, 1531 makeResourceCloseInvocation(resource)); 1532 return make.Block(0L, List.<JCStatement>of(closeIfStatement)); 1533 } 1534 1535 private JCStatement makeResourceCloseInvocation(JCExpression resource) { 1536 // create resource.close() method invocation 1537 JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil()); 1538 return make.Exec(resourceClose); 1539 } 1540 1541 /** Construct a tree that represents the outer instance 1542 * <C.this>. Never pick the current `this'. 1543 * @param pos The source code position to be used for the tree. 1544 * @param c The qualifier class. 1545 */ 1546 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { 1547 List<VarSymbol> ots = outerThisStack; 1548 if (ots.isEmpty()) { 1549 log.error(pos, "no.encl.instance.of.type.in.scope", c); 1550 assert false; 1551 return makeNull(); 1552 } 1553 VarSymbol ot = ots.head; 1554 JCExpression tree = access(make.at(pos).Ident(ot)); 1555 TypeSymbol otc = ot.type.tsym; 1556 while (otc != c) { 1557 do { 1558 ots = ots.tail; 1559 if (ots.isEmpty()) { 1560 log.error(pos, 3526 if (tree.name == names._class) 3527 result = classOf(tree.selected); 3528 else if (tree.name == names._this || tree.name == names._super) 3529 result = makeThis(tree.pos(), tree.selected.type.tsym); 3530 else 3531 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess); 3532 } 3533 3534 public void visitLetExpr(LetExpr tree) { 3535 tree.defs = translateVarDefs(tree.defs); 3536 tree.expr = translate(tree.expr, tree.type); 3537 result = tree; 3538 } 3539 3540 // There ought to be nothing to rewrite here; 3541 // we don't generate code. 3542 public void visitAnnotation(JCAnnotation tree) { 3543 result = tree; 3544 } 3545 3546 @Override 3547 public void visitTry(JCTry tree) { 3548 if (tree.resources.isEmpty()) { 3549 super.visitTry(tree); 3550 } else { 3551 result = makeArmTry(tree); 3552 } 3553 } 3554 3555 /************************************************************************** 3556 * main method 3557 *************************************************************************/ 3558 3559 /** Translate a toplevel class and return a list consisting of 3560 * the translated class and translated versions of all inner classes. 3561 * @param env The attribution environment current at the class definition. 3562 * We need this for resolving some additional symbols. 3563 * @param cdef The tree representing the class definition. 3564 */ 3565 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 3566 ListBuffer<JCTree> translated = null; 3567 try { 3568 attrEnv = env; 3569 this.make = make; 3570 endPositions = env.toplevel.endPositions; 3571 currentClass = null; 3572 currentMethodDef = null; 3573 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; 3574 outermostMemberDef = null; 3575 this.translated = new ListBuffer<JCTree>(); 3576 classdefs = new HashMap<ClassSymbol,JCClassDecl>(); 3577 actualSymbols = new HashMap<Symbol,Symbol>(); 3578 freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>(); 3579 proxies = new Scope(syms.noSymbol); 3580 armVars = new Scope(syms.noSymbol); 3581 outerThisStack = List.nil(); 3582 accessNums = new HashMap<Symbol,Integer>(); 3583 accessSyms = new HashMap<Symbol,MethodSymbol[]>(); 3584 accessConstrs = new HashMap<Symbol,MethodSymbol>(); 3585 accessConstrTags = List.nil(); 3586 accessed = new ListBuffer<Symbol>(); 3587 translate(cdef, (JCExpression)null); 3588 for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail) 3589 makeAccessible(l.head); 3590 for (EnumMapping map : enumSwitchMap.values()) 3591 map.translate(); 3592 checkConflicts(this.translated.toList()); 3593 checkAccessConstructorTags(); 3594 translated = this.translated; 3595 } finally { 3596 // note that recursive invocations of this method fail hard 3597 attrEnv = null; 3598 this.make = null; 3599 endPositions = null; 3600 currentClass = null; |