1736 }
1737
1738 @Override
1739 public boolean enterBlockStatement(final BlockStatement blockStatement) {
1740 if(!method.isReachable()) {
1741 return false;
1742 }
1743 enterStatement(blockStatement);
1744
1745 blockStatement.getBlock().accept(this);
1746
1747 return false;
1748 }
1749
1750 @Override
1751 public boolean enterForNode(final ForNode forNode) {
1752 if(!method.isReachable()) {
1753 return false;
1754 }
1755 enterStatement(forNode);
1756 if (forNode.isForIn()) {
1757 enterForIn(forNode);
1758 } else {
1759 final Expression init = forNode.getInit();
1760 if (init != null) {
1761 loadAndDiscard(init);
1762 }
1763 enterForOrWhile(forNode, forNode.getModify());
1764 }
1765
1766 return false;
1767 }
1768
1769 private void enterForIn(final ForNode forNode) {
1770 loadExpression(forNode.getModify(), TypeBounds.OBJECT);
1771 method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR);
1772 final Symbol iterSymbol = forNode.getIterator();
1773 final int iterSlot = iterSymbol.getSlot(Type.OBJECT);
1774 method.store(iterSymbol, ITERATOR_TYPE);
1775
1776 method.beforeJoinPoint(forNode);
1777
1778 final Label continueLabel = forNode.getContinueLabel();
1779 final Label breakLabel = forNode.getBreakLabel();
1780
1781 method.label(continueLabel);
1782 method.load(ITERATOR_TYPE, iterSlot);
1783 method.invoke(interfaceCallNoLookup(ITERATOR_CLASS, "hasNext", boolean.class));
1784 final JoinPredecessorExpression test = forNode.getTest();
1785 final Block body = forNode.getBody();
1786 if(LocalVariableConversion.hasLiveConversion(test)) {
1787 final Label afterConversion = new Label("for_in_after_test_conv");
1788 method.ifne(afterConversion);
1789 method.beforeJoinPoint(test);
1790 method._goto(breakLabel);
1791 method.label(afterConversion);
3301 }
3302
3303 @Override
3304 public boolean enterVarNode(final VarNode varNode) {
3305 if(!method.isReachable()) {
3306 return false;
3307 }
3308 final Expression init = varNode.getInit();
3309 final IdentNode identNode = varNode.getName();
3310 final Symbol identSymbol = identNode.getSymbol();
3311 assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
3312 final boolean needsScope = identSymbol.isScope();
3313
3314 if (init == null) {
3315 // Block-scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ).
3316 // However, don't do this for CONST which always has an initializer except in the special case of
3317 // for-in/of loops, in which it is initialized in the loop header and should be left untouched here.
3318 if (needsScope && varNode.isLet()) {
3319 method.loadCompilerConstant(SCOPE);
3320 method.loadUndefined(Type.OBJECT);
3321 final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
3322 assert isFastScope(identSymbol);
3323 storeFastScopeVar(identSymbol, flags);
3324 }
3325 return false;
3326 }
3327
3328 enterStatement(varNode);
3329 assert method != null;
3330
3331 if (needsScope) {
3332 method.loadCompilerConstant(SCOPE);
3333 loadExpressionUnbounded(init);
3334 // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
3335 final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
3336 if (isFastScope(identSymbol)) {
3337 storeFastScopeVar(identSymbol, flags);
3338 } else {
3339 method.dynamicSet(identNode.getName(), flags, false);
3340 }
3341 } else {
|
1736 }
1737
1738 @Override
1739 public boolean enterBlockStatement(final BlockStatement blockStatement) {
1740 if(!method.isReachable()) {
1741 return false;
1742 }
1743 enterStatement(blockStatement);
1744
1745 blockStatement.getBlock().accept(this);
1746
1747 return false;
1748 }
1749
1750 @Override
1751 public boolean enterForNode(final ForNode forNode) {
1752 if(!method.isReachable()) {
1753 return false;
1754 }
1755 enterStatement(forNode);
1756 if (forNode.isForInOrOf()) {
1757 enterForIn(forNode);
1758 } else {
1759 final Expression init = forNode.getInit();
1760 if (init != null) {
1761 loadAndDiscard(init);
1762 }
1763 enterForOrWhile(forNode, forNode.getModify());
1764 }
1765
1766 return false;
1767 }
1768
1769 private void enterForIn(final ForNode forNode) {
1770 loadExpression(forNode.getModify(), TypeBounds.OBJECT);
1771 if (forNode.isForEach()) {
1772 method.invoke(ScriptRuntime.TO_VALUE_ITERATOR);
1773 } else if (forNode.isForIn()) {
1774 method.invoke(ScriptRuntime.TO_PROPERTY_ITERATOR);
1775 } else if (forNode.isForOf()) {
1776 method.invoke(ScriptRuntime.TO_ES6_ITERATOR);
1777 } else {
1778 throw new IllegalArgumentException("Unexpected for node");
1779 }
1780 final Symbol iterSymbol = forNode.getIterator();
1781 final int iterSlot = iterSymbol.getSlot(Type.OBJECT);
1782 method.store(iterSymbol, ITERATOR_TYPE);
1783
1784 method.beforeJoinPoint(forNode);
1785
1786 final Label continueLabel = forNode.getContinueLabel();
1787 final Label breakLabel = forNode.getBreakLabel();
1788
1789 method.label(continueLabel);
1790 method.load(ITERATOR_TYPE, iterSlot);
1791 method.invoke(interfaceCallNoLookup(ITERATOR_CLASS, "hasNext", boolean.class));
1792 final JoinPredecessorExpression test = forNode.getTest();
1793 final Block body = forNode.getBody();
1794 if(LocalVariableConversion.hasLiveConversion(test)) {
1795 final Label afterConversion = new Label("for_in_after_test_conv");
1796 method.ifne(afterConversion);
1797 method.beforeJoinPoint(test);
1798 method._goto(breakLabel);
1799 method.label(afterConversion);
3309 }
3310
3311 @Override
3312 public boolean enterVarNode(final VarNode varNode) {
3313 if(!method.isReachable()) {
3314 return false;
3315 }
3316 final Expression init = varNode.getInit();
3317 final IdentNode identNode = varNode.getName();
3318 final Symbol identSymbol = identNode.getSymbol();
3319 assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
3320 final boolean needsScope = identSymbol.isScope();
3321
3322 if (init == null) {
3323 // Block-scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ).
3324 // However, don't do this for CONST which always has an initializer except in the special case of
3325 // for-in/of loops, in which it is initialized in the loop header and should be left untouched here.
3326 if (needsScope && varNode.isLet()) {
3327 method.loadCompilerConstant(SCOPE);
3328 method.loadUndefined(Type.OBJECT);
3329 final int flags = getScopeCallSiteFlags(identSymbol) | CALLSITE_DECLARE;
3330 assert isFastScope(identSymbol);
3331 storeFastScopeVar(identSymbol, flags);
3332 }
3333 return false;
3334 }
3335
3336 enterStatement(varNode);
3337 assert method != null;
3338
3339 if (needsScope) {
3340 method.loadCompilerConstant(SCOPE);
3341 loadExpressionUnbounded(init);
3342 // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
3343 final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
3344 if (isFastScope(identSymbol)) {
3345 storeFastScopeVar(identSymbol, flags);
3346 } else {
3347 method.dynamicSet(identNode.getName(), flags, false);
3348 }
3349 } else {
|