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