80 import jdk.nashorn.internal.runtime.Context;
81 import jdk.nashorn.internal.runtime.JSType;
82 import jdk.nashorn.internal.runtime.Source;
83 import jdk.nashorn.internal.runtime.logging.DebugLogger;
84 import jdk.nashorn.internal.runtime.logging.Loggable;
85 import jdk.nashorn.internal.runtime.logging.Logger;
86
87 /**
88 * Lower to more primitive operations. After lowering, an AST still has no symbols
89 * and types, but several nodes have been turned into more low level constructs
90 * and control flow termination criteria have been computed.
91 *
92 * We do things like code copying/inlining of finallies here, as it is much
93 * harder and context dependent to do any code copying after symbols have been
94 * finalized.
95 */
96 @Logger(name="lower")
97 final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Loggable {
98
99 private final DebugLogger log;
100
101 // Conservative pattern to test if element names consist of characters valid for identifiers.
102 // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
103 private static final Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*");
104
105 /**
106 * Constructor.
107 */
108 Lower(final Compiler compiler) {
109 super(new BlockLexicalContext() {
110
111 @Override
112 public List<Statement> popStatements() {
113 final List<Statement> newStatements = new ArrayList<>();
114 boolean terminated = false;
115
116 final List<Statement> statements = super.popStatements();
117 for (final Statement statement : statements) {
118 if (!terminated) {
119 newStatements.add(statement);
127 return newStatements;
128 }
129
130 @Override
131 protected Block afterSetStatements(final Block block) {
132 final List<Statement> stmts = block.getStatements();
133 for(final ListIterator<Statement> li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
134 final Statement stmt = li.previous();
135 // popStatements() guarantees that the only thing after a terminal statement are uninitialized
136 // VarNodes. We skip past those, and set the terminal state of the block to the value of the
137 // terminal state of the first statement that is not an uninitialized VarNode.
138 if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
139 return block.setIsTerminal(this, stmt.isTerminal());
140 }
141 }
142 return block.setIsTerminal(this, false);
143 }
144 });
145
146 this.log = initLogger(compiler.getContext());
147 }
148
149 @Override
150 public DebugLogger getLogger() {
151 return log;
152 }
153
154 @Override
155 public DebugLogger initLogger(final Context context) {
156 return context.getLogger(this.getClass());
157 }
158
159 @Override
160 public boolean enterBreakNode(final BreakNode breakNode) {
161 addStatement(breakNode);
162 return false;
163 }
164
165 @Override
166 public Node leaveCallNode(final CallNode callNode) {
240 }
241
242 return addStatement(node);
243 }
244
245 @Override
246 public Node leaveBlockStatement(final BlockStatement blockStatement) {
247 return addStatement(blockStatement);
248 }
249
250 @Override
251 public Node leaveForNode(final ForNode forNode) {
252 ForNode newForNode = forNode;
253
254 final Expression test = forNode.getTest();
255 if (!forNode.isForIn() && isAlwaysTrue(test)) {
256 newForNode = forNode.setTest(lc, null);
257 }
258
259 newForNode = checkEscape(newForNode);
260 if(newForNode.isForIn()) {
261 // Wrap it in a block so its internally created iterator is restricted in scope
262 addStatementEnclosedInBlock(newForNode);
263 } else {
264 addStatement(newForNode);
265 }
266 return newForNode;
267 }
268
269 @Override
270 public Node leaveFunctionNode(final FunctionNode functionNode) {
271 log.info("END FunctionNode: ", functionNode.getName());
272 return functionNode;
273 }
274
275 @Override
276 public Node leaveIfNode(final IfNode ifNode) {
277 return addStatement(ifNode);
278 }
279
280 @Override
281 public Node leaveIN(final BinaryNode binaryNode) {
|
80 import jdk.nashorn.internal.runtime.Context;
81 import jdk.nashorn.internal.runtime.JSType;
82 import jdk.nashorn.internal.runtime.Source;
83 import jdk.nashorn.internal.runtime.logging.DebugLogger;
84 import jdk.nashorn.internal.runtime.logging.Loggable;
85 import jdk.nashorn.internal.runtime.logging.Logger;
86
87 /**
88 * Lower to more primitive operations. After lowering, an AST still has no symbols
89 * and types, but several nodes have been turned into more low level constructs
90 * and control flow termination criteria have been computed.
91 *
92 * We do things like code copying/inlining of finallies here, as it is much
93 * harder and context dependent to do any code copying after symbols have been
94 * finalized.
95 */
96 @Logger(name="lower")
97 final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Loggable {
98
99 private final DebugLogger log;
100 private final boolean es6;
101
102 // Conservative pattern to test if element names consist of characters valid for identifiers.
103 // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
104 private static final Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*");
105
106 /**
107 * Constructor.
108 */
109 Lower(final Compiler compiler) {
110 super(new BlockLexicalContext() {
111
112 @Override
113 public List<Statement> popStatements() {
114 final List<Statement> newStatements = new ArrayList<>();
115 boolean terminated = false;
116
117 final List<Statement> statements = super.popStatements();
118 for (final Statement statement : statements) {
119 if (!terminated) {
120 newStatements.add(statement);
128 return newStatements;
129 }
130
131 @Override
132 protected Block afterSetStatements(final Block block) {
133 final List<Statement> stmts = block.getStatements();
134 for(final ListIterator<Statement> li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
135 final Statement stmt = li.previous();
136 // popStatements() guarantees that the only thing after a terminal statement are uninitialized
137 // VarNodes. We skip past those, and set the terminal state of the block to the value of the
138 // terminal state of the first statement that is not an uninitialized VarNode.
139 if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
140 return block.setIsTerminal(this, stmt.isTerminal());
141 }
142 }
143 return block.setIsTerminal(this, false);
144 }
145 });
146
147 this.log = initLogger(compiler.getContext());
148 this.es6 = compiler.getScriptEnvironment()._es6;
149 }
150
151 @Override
152 public DebugLogger getLogger() {
153 return log;
154 }
155
156 @Override
157 public DebugLogger initLogger(final Context context) {
158 return context.getLogger(this.getClass());
159 }
160
161 @Override
162 public boolean enterBreakNode(final BreakNode breakNode) {
163 addStatement(breakNode);
164 return false;
165 }
166
167 @Override
168 public Node leaveCallNode(final CallNode callNode) {
242 }
243
244 return addStatement(node);
245 }
246
247 @Override
248 public Node leaveBlockStatement(final BlockStatement blockStatement) {
249 return addStatement(blockStatement);
250 }
251
252 @Override
253 public Node leaveForNode(final ForNode forNode) {
254 ForNode newForNode = forNode;
255
256 final Expression test = forNode.getTest();
257 if (!forNode.isForIn() && isAlwaysTrue(test)) {
258 newForNode = forNode.setTest(lc, null);
259 }
260
261 newForNode = checkEscape(newForNode);
262 if(!es6 && newForNode.isForIn()) {
263 // Wrap it in a block so its internally created iterator is restricted in scope, unless we are running
264 // in ES6 mode, in which case the parser already created a block to capture let/const declarations.
265 addStatementEnclosedInBlock(newForNode);
266 } else {
267 addStatement(newForNode);
268 }
269 return newForNode;
270 }
271
272 @Override
273 public Node leaveFunctionNode(final FunctionNode functionNode) {
274 log.info("END FunctionNode: ", functionNode.getName());
275 return functionNode;
276 }
277
278 @Override
279 public Node leaveIfNode(final IfNode ifNode) {
280 return addStatement(ifNode);
281 }
282
283 @Override
284 public Node leaveIN(final BinaryNode binaryNode) {
|