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 } 622 while (lookupSynthetic(name, s) != null); 623 return name; 624 } 625 626 /** Check whether synthetic symbols generated during lowering conflict 627 * with user-defined symbols. 628 * 629 * @param translatedTrees lowered class trees 630 */ 631 void checkConflicts(List<JCTree> translatedTrees) { 632 for (JCTree t : translatedTrees) { 633 t.accept(conflictsChecker); 634 } 635 } 636 637 JCTree.Visitor conflictsChecker = new TreeScanner() { 638 639 TypeSymbol currentClass; 640 641 @Override 642 public void visitMethodDef(JCMethodDecl that) { 643 chk.checkConflicts(that.pos(), that.sym, currentClass); 644 super.visitMethodDef(that); 645 } 1300 make.Call( 1301 make.App( 1302 callee, 1303 make.Idents(md.params.reverse().tail.reverse()))))); 1304 return md; 1305 } 1306 1307 /************************************************************************** 1308 * Free variables proxies and this$n 1309 *************************************************************************/ 1310 1311 /** A scope containing all free variable proxies for currently translated 1312 * class, as well as its this$n symbol (if needed). 1313 * Proxy scopes are nested in the same way classes are. 1314 * Inside a constructor, proxies and any this$n symbol are duplicated 1315 * in an additional innermost scope, where they represent the constructor 1316 * parameters. 1317 */ 1318 Scope proxies; 1319 1320 /** A scope containing all unnamed resource variables/saved exception variables 1321 * for translated ARM blocks 1322 */ 1323 Scope armVars; 1324 1325 /** A stack containing the this$n field of the currently translated 1326 * classes (if needed) in innermost first order. 1327 * Inside a constructor, proxies and any this$n symbol are duplicated 1328 * in an additional innermost scope, where they represent the constructor 1329 * parameters. 1330 */ 1331 List<VarSymbol> outerThisStack; 1332 1333 /** The name of a free variable proxy. 1334 */ 1335 Name proxyName(Name name) { 1336 return names.fromString("val" + target.syntheticNameChar() + name); 1337 } 1338 1339 /** Proxy definitions for all free variables in given list, in reverse order. 1340 * @param pos The source code position of the definition. 1341 * @param freevars The free variables. 1342 * @param owner The class in which the definitions go. 1343 */ 1344 List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) { 1406 } 1407 //where 1408 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) { 1409 return access(v, make.at(pos).Ident(v), null, false); 1410 } 1411 1412 /** Construct a tree simulating the expression <C.this>. 1413 * @param pos The source code position to be used for the tree. 1414 * @param c The qualifier class. 1415 */ 1416 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) { 1417 if (currentClass == c) { 1418 // in this case, `this' works fine 1419 return make.at(pos).This(c.erasure(types)); 1420 } else { 1421 // need to go via this$n 1422 return makeOuterThis(pos, c); 1423 } 1424 } 1425 1426 /** Optionally replace a try statement with an automatic resource management 1427 * (ARM) block. 1428 * @param tree The try statement to inspect. 1429 * @return An ARM block, or the original try block if there are no 1430 * resources to manage. 1431 */ 1432 JCTree makeArmTry(JCTry tree) { 1433 make_at(tree.pos()); 1434 armVars = armVars.dup(); 1435 JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0); 1436 if (tree.catchers.isEmpty() && tree.finalizer == null) 1437 result = translate(armBlock); 1438 else 1439 result = translate(make.Try(armBlock, tree.catchers, tree.finalizer)); 1440 armVars = armVars.leave(); 1441 return result; 1442 } 1443 1444 private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) { 1445 if (resources.isEmpty()) 1446 return block; 1447 1448 // Add resource declaration or expression to block statements 1449 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); 1450 JCTree resource = resources.head; 1451 JCExpression expr = null; 1452 if (resource instanceof JCVariableDecl) { 1453 JCVariableDecl var = (JCVariableDecl) resource; 1454 expr = make.Ident(var.sym).setType(resource.type); 1455 stats.add(var); 1456 } else { 1457 assert resource instanceof JCExpression; 1458 VarSymbol syntheticArmVar = 1459 new VarSymbol(SYNTHETIC | FINAL, 1460 makeSyntheticName(names.fromString("armVar" + 1461 depth), armVars), 1462 (resource.type.tag == TypeTags.BOT) ? 1463 syms.autoCloseableType : resource.type, 1464 currentMethodSym); 1465 armVars.enter(syntheticArmVar); 1466 JCVariableDecl syntheticArmVarDecl = 1467 make.VarDef(syntheticArmVar, (JCExpression)resource); 1468 expr = (JCExpression)make.Ident(syntheticArmVar); 1469 stats.add(syntheticArmVarDecl); 1470 } 1471 1472 // Add primaryException declaration 1473 VarSymbol primaryException = 1474 new VarSymbol(SYNTHETIC, 1475 makeSyntheticName(names.fromString("primaryException" + 1476 depth), armVars), 1477 syms.throwableType, 1478 currentMethodSym); 1479 armVars.enter(primaryException); 1480 JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); 1481 stats.add(primaryExceptionTreeDecl); 1482 1483 // Create catch clause that saves exception and then rethrows it 1484 VarSymbol param = 1485 new VarSymbol(FINAL|SYNTHETIC, 1486 names.fromString("t" + 1487 target.syntheticNameChar()), 1488 syms.throwableType, 1489 currentMethodSym); 1490 JCVariableDecl paramTree = make.VarDef(param, null); 1491 JCStatement assign = make.Assignment(primaryException, make.Ident(param)); 1492 JCStatement rethrowStat = make.Throw(make.Ident(param)); 1493 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat)); 1494 JCCatch catchClause = make.Catch(paramTree, catchBlock); 1495 1496 int oldPos = make.pos; 1497 make.at(TreeInfo.endPos(block)); 1498 JCBlock finallyClause = makeArmFinallyClause(primaryException, expr); 1499 make.at(oldPos); 1500 JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1), 1501 List.<JCCatch>of(catchClause), 1502 finallyClause); 1503 stats.add(outerTry); 1504 return make.Block(0L, stats.toList()); 1505 } 1506 1507 private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) { 1508 // primaryException.addSuppressedException(catchException); 1509 VarSymbol catchException = 1510 new VarSymbol(0, make.paramName(2), 1511 syms.throwableType, 1512 currentMethodSym); 1513 JCStatement addSuppressionStatement = 1514 make.Exec(makeCall(make.Ident(primaryException), 1515 names.fromString("addSuppressedException"), 1516 List.<JCExpression>of(make.Ident(catchException)))); 1517 1518 // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } 1519 JCBlock tryBlock = 1520 make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource))); 1521 JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); 1522 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement)); 1523 List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock)); 1524 JCTry tryTree = make.Try(tryBlock, catchClauses, null); 1525 1526 // if (resource != null) resourceClose; 1527 JCExpression nullCheck = makeBinary(JCTree.NE, 1528 make.Ident(primaryException), 1529 makeNull()); 1530 JCIf closeIfStatement = make.If(nullCheck, 1531 tryTree, 1532 makeResourceCloseInvocation(resource)); 1533 return make.Block(0L, List.<JCStatement>of(closeIfStatement)); 1534 } 1535 1536 private JCStatement makeResourceCloseInvocation(JCExpression resource) { 1537 // create resource.close() method invocation 1538 JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil()); 1539 return make.Exec(resourceClose); 1540 } 1541 1542 /** Construct a tree that represents the outer instance 1543 * <C.this>. Never pick the current `this'. 1544 * @param pos The source code position to be used for the tree. 1545 * @param c The qualifier class. 1546 */ 1547 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { 1548 List<VarSymbol> ots = outerThisStack; 1549 if (ots.isEmpty()) { 1550 log.error(pos, "no.encl.instance.of.type.in.scope", c); 1551 assert false; 1552 return makeNull(); 1553 } 1554 VarSymbol ot = ots.head; 1555 JCExpression tree = access(make.at(pos).Ident(ot)); 1556 TypeSymbol otc = ot.type.tsym; 1557 while (otc != c) { 1558 do { 1559 ots = ots.tail; 1560 if (ots.isEmpty()) { 1561 log.error(pos, 3527 if (tree.name == names._class) 3528 result = classOf(tree.selected); 3529 else if (tree.name == names._this || tree.name == names._super) 3530 result = makeThis(tree.pos(), tree.selected.type.tsym); 3531 else 3532 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess); 3533 } 3534 3535 public void visitLetExpr(LetExpr tree) { 3536 tree.defs = translateVarDefs(tree.defs); 3537 tree.expr = translate(tree.expr, tree.type); 3538 result = tree; 3539 } 3540 3541 // There ought to be nothing to rewrite here; 3542 // we don't generate code. 3543 public void visitAnnotation(JCAnnotation tree) { 3544 result = tree; 3545 } 3546 3547 @Override 3548 public void visitTry(JCTry tree) { 3549 if (tree.resources.isEmpty()) { 3550 super.visitTry(tree); 3551 } else { 3552 result = makeArmTry(tree); 3553 } 3554 } 3555 3556 /************************************************************************** 3557 * main method 3558 *************************************************************************/ 3559 3560 /** Translate a toplevel class and return a list consisting of 3561 * the translated class and translated versions of all inner classes. 3562 * @param env The attribution environment current at the class definition. 3563 * We need this for resolving some additional symbols. 3564 * @param cdef The tree representing the class definition. 3565 */ 3566 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 3567 ListBuffer<JCTree> translated = null; 3568 try { 3569 attrEnv = env; 3570 this.make = make; 3571 endPositions = env.toplevel.endPositions; 3572 currentClass = null; 3573 currentMethodDef = null; 3574 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; 3575 outermostMemberDef = null; 3576 this.translated = new ListBuffer<JCTree>(); 3577 classdefs = new HashMap<ClassSymbol,JCClassDecl>(); 3578 actualSymbols = new HashMap<Symbol,Symbol>(); 3579 freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>(); 3580 proxies = new Scope(syms.noSymbol); 3581 armVars = new Scope(syms.noSymbol); 3582 outerThisStack = List.nil(); 3583 accessNums = new HashMap<Symbol,Integer>(); 3584 accessSyms = new HashMap<Symbol,MethodSymbol[]>(); 3585 accessConstrs = new HashMap<Symbol,MethodSymbol>(); 3586 accessConstrTags = List.nil(); 3587 accessed = new ListBuffer<Symbol>(); 3588 translate(cdef, (JCExpression)null); 3589 for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail) 3590 makeAccessible(l.head); 3591 for (EnumMapping map : enumSwitchMap.values()) 3592 map.translate(); 3593 checkConflicts(this.translated.toList()); 3594 checkAccessConstructorTags(); 3595 translated = this.translated; 3596 } finally { 3597 // note that recursive invocations of this method fail hard 3598 attrEnv = null; 3599 this.make = null; 3600 endPositions = null; 3601 currentClass = null; |