Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library code_generator; 5 library code_generator;
6 6
7 import 'glue.dart'; 7 import 'glue.dart';
8 8
9 import '../../closure.dart' show 9 import '../../closure.dart' show ClosureClassElement;
10 ClosureClassElement; 10 import '../../common/codegen.dart' show CodegenRegistry;
11 import '../../common/codegen.dart' show
12 CodegenRegistry;
13 import '../../constants/values.dart'; 11 import '../../constants/values.dart';
14 import '../../dart_types.dart'; 12 import '../../dart_types.dart';
15 import '../../elements/elements.dart'; 13 import '../../elements/elements.dart';
16 import '../../io/source_information.dart' show 14 import '../../io/source_information.dart' show SourceInformation;
17 SourceInformation;
18 import '../../js/js.dart' as js; 15 import '../../js/js.dart' as js;
19 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; 16 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
20 import '../../tree_ir/tree_ir_nodes.dart' show 17 import '../../tree_ir/tree_ir_nodes.dart'
21 BuiltinMethod, 18 show BuiltinMethod, BuiltinOperator, isCompoundableOperator;
22 BuiltinOperator, 19 import '../../types/types.dart' show TypeMask;
23 isCompoundableOperator; 20 import '../../universe/call_structure.dart' show CallStructure;
24 import '../../types/types.dart' show 21 import '../../universe/selector.dart' show Selector;
25 TypeMask; 22 import '../../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
26 import '../../universe/call_structure.dart' show
27 CallStructure;
28 import '../../universe/selector.dart' show
29 Selector;
30 import '../../universe/use.dart' show
31 DynamicUse,
32 StaticUse,
33 TypeUse;
34 import '../../util/maplet.dart'; 23 import '../../util/maplet.dart';
35 24
36 class CodegenBailout { 25 class CodegenBailout {
37 final tree_ir.Node node; 26 final tree_ir.Node node;
38 final String reason; 27 final String reason;
39 CodegenBailout(this.node, this.reason); 28 CodegenBailout(this.node, this.reason);
40 String get message { 29 String get message {
41 return 'bailout${node != null ? " on $node" : ""}: $reason'; 30 return 'bailout${node != null ? " on $node" : ""}: $reason';
42 } 31 }
43 } 32 }
44 33
45 class CodeGenerator extends tree_ir.StatementVisitor 34 class CodeGenerator extends tree_ir.StatementVisitor
46 with tree_ir.ExpressionVisitor<js.Expression> { 35 with tree_ir.ExpressionVisitor<js.Expression> {
47 final CodegenRegistry registry; 36 final CodegenRegistry registry;
48 37
49 final Glue glue; 38 final Glue glue;
50 39
51 ExecutableElement currentFunction; 40 ExecutableElement currentFunction;
52 41
53 /// Maps variables to their name. 42 /// Maps variables to their name.
54 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; 43 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
55 44
56 /// Maps local constants to their name. 45 /// Maps local constants to their name.
57 Maplet<VariableElement, String> constantNames = 46 Maplet<VariableElement, String> constantNames =
58 new Maplet<VariableElement, String>(); 47 new Maplet<VariableElement, String>();
59 48
60 /// Variable names that have already been used. Used to avoid name clashes. 49 /// Variable names that have already been used. Used to avoid name clashes.
61 Set<String> usedVariableNames = new Set<String>(); 50 Set<String> usedVariableNames = new Set<String>();
62 51
63 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); 52 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
64 53
65 /// Stacks whose top element is the current target of an unlabeled break 54 /// Stacks whose top element is the current target of an unlabeled break
66 /// or continue. For continues, this is the loop node itself. 55 /// or continue. For continues, this is the loop node itself.
67 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); 56 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack();
68 final tree_ir.FallthroughStack shortContinue = 57 final tree_ir.FallthroughStack shortContinue = new tree_ir.FallthroughStack();
69 new tree_ir.FallthroughStack();
70 58
71 /// When the top element is true, [Unreachable] statements will be emitted 59 /// When the top element is true, [Unreachable] statements will be emitted
72 /// as [Return]s, otherwise they are emitted as empty because they are 60 /// as [Return]s, otherwise they are emitted as empty because they are
73 /// followed by the end of the method. 61 /// followed by the end of the method.
74 /// 62 ///
75 /// Note on why the [fallthrough] stack should not be used for this: 63 /// Note on why the [fallthrough] stack should not be used for this:
76 /// Ordinary statements may choose whether to use the [fallthrough] target, 64 /// Ordinary statements may choose whether to use the [fallthrough] target,
77 /// and the choice to do so may disable an optimization in [visitIf]. 65 /// and the choice to do so may disable an optimization in [visitIf].
78 /// But omitting an unreachable 'return' should have lower priority than 66 /// But omitting an unreachable 'return' should have lower priority than
79 /// the optimizations in [visitIf], so [visitIf] will instead tell the 67 /// the optimizations in [visitIf], so [visitIf] will instead tell the
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 if (assign.op != null) break; // Compound assignment. 111 if (assign.op != null) break; // Compound assignment.
124 js.VariableUse use = assign.leftHandSide; 112 js.VariableUse use = assign.leftHandSide;
125 113
126 // Do not touch non-local variables. 114 // Do not touch non-local variables.
127 if (!usedVariableNames.contains(use.name)) break; 115 if (!usedVariableNames.contains(use.name)) break;
128 116
129 // We cannot declare a variable more than once. 117 // We cannot declare a variable more than once.
130 if (!declaredVariables.add(use.name)) break; 118 if (!declaredVariables.add(use.name)) break;
131 119
132 js.VariableInitialization jsVariable = new js.VariableInitialization( 120 js.VariableInitialization jsVariable = new js.VariableInitialization(
133 new js.VariableDeclaration(use.name), 121 new js.VariableDeclaration(use.name), assign.value);
134 assign.value);
135 jsVariables.add(jsVariable); 122 jsVariables.add(jsVariable);
136 123
137 ++accumulatorIndex; 124 ++accumulatorIndex;
138 } 125 }
139 126
140 // If the last statement is a for loop with an initializer expression, try 127 // If the last statement is a for loop with an initializer expression, try
141 // to pull that expression into an initializer as well. 128 // to pull that expression into an initializer as well.
142 pullFromForLoop: 129 pullFromForLoop: if (accumulatorIndex < accumulator.length &&
143 if (accumulatorIndex < accumulator.length &&
144 accumulator[accumulatorIndex] is js.For) { 130 accumulator[accumulatorIndex] is js.For) {
145 js.For forLoop = accumulator[accumulatorIndex]; 131 js.For forLoop = accumulator[accumulatorIndex];
146 if (forLoop.init is! js.Assignment) break pullFromForLoop; 132 if (forLoop.init is! js.Assignment) break pullFromForLoop;
147 js.Assignment assign = forLoop.init; 133 js.Assignment assign = forLoop.init;
148 if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop; 134 if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop;
149 if (assign.op != null) break pullFromForLoop; // Compound assignment. 135 if (assign.op != null) break pullFromForLoop; // Compound assignment.
150 js.VariableUse use = assign.leftHandSide; 136 js.VariableUse use = assign.leftHandSide;
151 137
152 // Do not touch non-local variables. 138 // Do not touch non-local variables.
153 if (!usedVariableNames.contains(use.name)) break pullFromForLoop; 139 if (!usedVariableNames.contains(use.name)) break pullFromForLoop;
154 140
155 // We cannot declare a variable more than once. 141 // We cannot declare a variable more than once.
156 if (!declaredVariables.add(use.name)) break pullFromForLoop; 142 if (!declaredVariables.add(use.name)) break pullFromForLoop;
157 143
158 js.VariableInitialization jsVariable = new js.VariableInitialization( 144 js.VariableInitialization jsVariable = new js.VariableInitialization(
159 new js.VariableDeclaration(use.name), 145 new js.VariableDeclaration(use.name), assign.value);
160 assign.value);
161 jsVariables.add(jsVariable); 146 jsVariables.add(jsVariable);
162 147
163 // Remove the initializer from the for loop. 148 // Remove the initializer from the for loop.
164 accumulator[accumulatorIndex] = 149 accumulator[accumulatorIndex] =
165 new js.For(null, forLoop.condition, forLoop.update, forLoop.body); 150 new js.For(null, forLoop.condition, forLoop.update, forLoop.body);
166 } 151 }
167 152
168 // Discard the statements that were pulled in the initializer. 153 // Discard the statements that were pulled in the initializer.
169 if (accumulatorIndex > 0) { 154 if (accumulatorIndex > 0) {
170 accumulator = accumulator.sublist(accumulatorIndex); 155 accumulator = accumulator.sublist(accumulatorIndex);
171 } 156 }
172 157
173 // Declare remaining variables. 158 // Declare remaining variables.
174 for (tree_ir.Variable variable in variableNames.keys) { 159 for (tree_ir.Variable variable in variableNames.keys) {
175 String name = getVariableName(variable); 160 String name = getVariableName(variable);
176 if (declaredVariables.contains(name)) continue; 161 if (declaredVariables.contains(name)) continue;
177 js.VariableInitialization jsVariable = new js.VariableInitialization( 162 js.VariableInitialization jsVariable =
178 new js.VariableDeclaration(name), 163 new js.VariableInitialization(new js.VariableDeclaration(name), null);
179 null);
180 jsVariables.add(jsVariable); 164 jsVariables.add(jsVariable);
181 } 165 }
182 166
183 if (jsVariables.length > 0) { 167 if (jsVariables.length > 0) {
184 // Would be nice to avoid inserting at the beginning of list. 168 // Would be nice to avoid inserting at the beginning of list.
185 accumulator.insert(0, new js.ExpressionStatement( 169 accumulator.insert(
186 new js.VariableDeclarationList(jsVariables) 170 0,
171 new js.ExpressionStatement(new js.VariableDeclarationList(jsVariables)
187 .withSourceInformation(function.sourceInformation))); 172 .withSourceInformation(function.sourceInformation)));
188 } 173 }
189 return new js.Fun(parameters, new js.Block(accumulator)); 174 return new js.Fun(parameters, new js.Block(accumulator));
190 } 175 }
191 176
192 @override 177 @override
193 js.Expression visitExpression(tree_ir.Expression node) { 178 js.Expression visitExpression(tree_ir.Expression node) {
194 js.Expression result = node.accept(this); 179 js.Expression result = node.accept(this);
195 if (result == null) { 180 if (result == null) {
196 glue.reportInternalError('$node did not produce code.'); 181 glue.reportInternalError('$node did not produce code.');
197 } 182 }
198 return result; 183 return result;
199 } 184 }
200 185
201 /// Generates a name for the given variable. First trying with the name of 186 /// Generates a name for the given variable. First trying with the name of
202 /// the [Variable.element] if it is non-null. 187 /// the [Variable.element] if it is non-null.
203 String getVariableName(tree_ir.Variable variable) { 188 String getVariableName(tree_ir.Variable variable) {
204 // Functions are not nested in the JS backend. 189 // Functions are not nested in the JS backend.
205 assert(variable.host == currentFunction); 190 assert(variable.host == currentFunction);
206 191
207 // Get the name if we already have one. 192 // Get the name if we already have one.
208 String name = variableNames[variable]; 193 String name = variableNames[variable];
209 if (name != null) { 194 if (name != null) {
210 return name; 195 return name;
211 } 196 }
212 197
213 // Synthesize a variable name that isn't used elsewhere. 198 // Synthesize a variable name that isn't used elsewhere.
214 String prefix = variable.element == null ? 'v' : variable.element.name; 199 String prefix = variable.element == null ? 'v' : variable.element.name;
215 int counter = 0; 200 int counter = 0;
216 name = glue.safeVariableName(variable.element == null 201 name = glue.safeVariableName(
217 ? '$prefix$counter' 202 variable.element == null ? '$prefix$counter' : variable.element.name);
218 : variable.element.name);
219 while (!usedVariableNames.add(name)) { 203 while (!usedVariableNames.add(name)) {
220 ++counter; 204 ++counter;
221 name = '$prefix$counter'; 205 name = '$prefix$counter';
222 } 206 }
223 variableNames[variable] = name; 207 variableNames[variable] = name;
224 208
225 return name; 209 return name;
226 } 210 }
227 211
228 List<js.Expression> visitExpressionList( 212 List<js.Expression> visitExpressionList(
229 List<tree_ir.Expression> expressions) { 213 List<tree_ir.Expression> expressions) {
230 List<js.Expression> result = new List<js.Expression>(expressions.length); 214 List<js.Expression> result = new List<js.Expression>(expressions.length);
231 for (int i = 0; i < expressions.length; ++i) { 215 for (int i = 0; i < expressions.length; ++i) {
232 result[i] = visitExpression(expressions[i]); 216 result[i] = visitExpression(expressions[i]);
233 } 217 }
234 return result; 218 return result;
235 } 219 }
236 220
237 giveup(tree_ir.Node node, 221 giveup(tree_ir.Node node,
238 [String reason = 'unimplemented in CodeGenerator']) { 222 [String reason = 'unimplemented in CodeGenerator']) {
239 throw new CodegenBailout(node, reason); 223 throw new CodegenBailout(node, reason);
240 } 224 }
241 225
242 @override 226 @override
243 js.Expression visitConditional(tree_ir.Conditional node) { 227 js.Expression visitConditional(tree_ir.Conditional node) {
244 return new js.Conditional( 228 return new js.Conditional(
245 visitExpression(node.condition), 229 visitExpression(node.condition),
246 visitExpression(node.thenExpression), 230 visitExpression(node.thenExpression),
247 visitExpression(node.elseExpression)); 231 visitExpression(node.elseExpression));
248 } 232 }
249 233
250 js.Expression buildConstant(ConstantValue constant, 234 js.Expression buildConstant(ConstantValue constant,
251 {SourceInformation sourceInformation}) { 235 {SourceInformation sourceInformation}) {
252 registry.registerCompileTimeConstant(constant); 236 registry.registerCompileTimeConstant(constant);
253 return glue.constantReference(constant) 237 return glue
238 .constantReference(constant)
254 .withSourceInformation(sourceInformation); 239 .withSourceInformation(sourceInformation);
255 } 240 }
256 241
257 @override 242 @override
258 js.Expression visitConstant(tree_ir.Constant node) { 243 js.Expression visitConstant(tree_ir.Constant node) {
259 return buildConstant( 244 return buildConstant(node.value, sourceInformation: node.sourceInformation);
260 node.value,
261 sourceInformation: node.sourceInformation);
262 } 245 }
263 246
264 js.Expression buildStaticInvoke(Element target, 247 js.Expression buildStaticInvoke(Element target, List<js.Expression> arguments,
265 List<js.Expression> arguments, 248 {SourceInformation sourceInformation}) {
266 {SourceInformation sourceInformation}) {
267 if (target.isConstructor) { 249 if (target.isConstructor) {
268 // TODO(johnniwinther): Avoid dependency on [isGenerativeConstructor] by 250 // TODO(johnniwinther): Avoid dependency on [isGenerativeConstructor] by
269 // using backend-specific [StatisUse] classes. 251 // using backend-specific [StatisUse] classes.
270 registry.registerStaticUse( 252 registry.registerStaticUse(new StaticUse.constructorInvoke(
271 new StaticUse.constructorInvoke(target.declaration, 253 target.declaration, new CallStructure.unnamed(arguments.length)));
272 new CallStructure.unnamed(arguments.length)));
273 } else { 254 } else {
274 registry.registerStaticUse( 255 registry.registerStaticUse(new StaticUse.staticInvoke(
275 new StaticUse.staticInvoke(target.declaration, 256 target.declaration, new CallStructure.unnamed(arguments.length)));
276 new CallStructure.unnamed(arguments.length)));
277 } 257 }
278 js.Expression elementAccess = glue.staticFunctionAccess(target); 258 js.Expression elementAccess = glue.staticFunctionAccess(target);
279 return new js.Call(elementAccess, arguments, 259 return new js.Call(elementAccess, arguments,
280 sourceInformation: sourceInformation); 260 sourceInformation: sourceInformation);
281 } 261 }
282 262
283 @override 263 @override
284 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { 264 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
285 if (node.constant != null) return giveup(node); 265 if (node.constant != null) return giveup(node);
286 266
287 registry.registerInstantiation(node.type); 267 registry.registerInstantiation(node.type);
288 FunctionElement target = node.target; 268 FunctionElement target = node.target;
289 List<js.Expression> arguments = visitExpressionList(node.arguments); 269 List<js.Expression> arguments = visitExpressionList(node.arguments);
290 return buildStaticInvoke( 270 return buildStaticInvoke(target, arguments,
291 target,
292 arguments,
293 sourceInformation: node.sourceInformation); 271 sourceInformation: node.sourceInformation);
294 } 272 }
295 273
296 void registerMethodInvoke(Selector selector, TypeMask receiverType) { 274 void registerMethodInvoke(Selector selector, TypeMask receiverType) {
297 registry.registerDynamicUse(new DynamicUse(selector, receiverType)); 275 registry.registerDynamicUse(new DynamicUse(selector, receiverType));
298 if (!selector.isGetter && !selector.isSetter) { 276 if (!selector.isGetter && !selector.isSetter) {
299 // TODO(sigurdm): We should find a better place to register the call. 277 // TODO(sigurdm): We should find a better place to register the call.
300 Selector call = new Selector.callClosureFrom(selector); 278 Selector call = new Selector.callClosureFrom(selector);
301 registry.registerDynamicUse(new DynamicUse(call, null)); 279 registry.registerDynamicUse(new DynamicUse(call, null));
302 } 280 }
303 } 281 }
304 282
305 @override 283 @override
306 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { 284 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) {
307 TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask); 285 TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask);
308 registerMethodInvoke(node.selector, mask); 286 registerMethodInvoke(node.selector, mask);
309 return js.propertyCall(visitExpression(node.receiver), 287 return js
310 glue.invocationName(node.selector), 288 .propertyCall(
311 visitExpressionList(node.arguments)) 289 visitExpression(node.receiver),
290 glue.invocationName(node.selector),
291 visitExpressionList(node.arguments))
312 .withSourceInformation(node.sourceInformation); 292 .withSourceInformation(node.sourceInformation);
313 } 293 }
314 294
315 @override 295 @override
316 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { 296 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) {
317 FunctionElement target = node.target; 297 FunctionElement target = node.target;
318 List<js.Expression> arguments = visitExpressionList(node.arguments); 298 List<js.Expression> arguments = visitExpressionList(node.arguments);
319 return buildStaticInvoke(target, arguments, 299 return buildStaticInvoke(target, arguments,
320 sourceInformation: node.sourceInformation); 300 sourceInformation: node.sourceInformation);
321 } 301 }
322 302
323 @override 303 @override
324 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { 304 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) {
325 if (node.isTearOff) { 305 if (node.isTearOff) {
326 // If this is a tear-off, register the fact that a tear-off closure 306 // If this is a tear-off, register the fact that a tear-off closure
327 // will be created, and that this tear-off must bypass ordinary 307 // will be created, and that this tear-off must bypass ordinary
328 // dispatch to ensure the super method is invoked. 308 // dispatch to ensure the super method is invoked.
329 registry.registerStaticUse(new StaticUse.staticInvoke( 309 registry.registerStaticUse(new StaticUse.staticInvoke(
330 glue.closureFromTearOff, new CallStructure.unnamed( 310 glue.closureFromTearOff,
331 glue.closureFromTearOff.parameters.length))); 311 new CallStructure.unnamed(
312 glue.closureFromTearOff.parameters.length)));
332 registry.registerStaticUse(new StaticUse.superTearOff(node.target)); 313 registry.registerStaticUse(new StaticUse.superTearOff(node.target));
333 } 314 }
334 if (node.target is ConstructorBodyElement) { 315 if (node.target is ConstructorBodyElement) {
335 registry.registerStaticUse( 316 registry.registerStaticUse(new StaticUse.constructorBodyInvoke(
336 new StaticUse.constructorBodyInvoke( 317 node.target.declaration,
337 node.target.declaration, 318 new CallStructure.unnamed(node.arguments.length)));
338 new CallStructure.unnamed(node.arguments.length)));
339 // A constructor body cannot be overriden or intercepted, so we can 319 // A constructor body cannot be overriden or intercepted, so we can
340 // use the short form for this invocation. 320 // use the short form for this invocation.
341 return js.js('#.#(#)', 321 return js.js('#.#(#)', [
342 [visitExpression(node.receiver), 322 visitExpression(node.receiver),
343 glue.instanceMethodName(node.target), 323 glue.instanceMethodName(node.target),
344 visitExpressionList(node.arguments)]) 324 visitExpressionList(node.arguments)
345 .withSourceInformation(node.sourceInformation); 325 ]).withSourceInformation(node.sourceInformation);
346 } 326 }
347 registry.registerStaticUse( 327 registry.registerStaticUse(new StaticUse.superInvoke(
348 new StaticUse.superInvoke( 328 node.target.declaration,
349 node.target.declaration, 329 new CallStructure.unnamed(node.arguments.length)));
350 new CallStructure.unnamed(node.arguments.length))); 330 return js.js('#.#.call(#, #)', [
351 return js.js('#.#.call(#, #)', 331 glue.prototypeAccess(node.target.enclosingClass),
352 [glue.prototypeAccess(node.target.enclosingClass), 332 glue.invocationName(node.selector),
353 glue.invocationName(node.selector), 333 visitExpression(node.receiver),
354 visitExpression(node.receiver), 334 visitExpressionList(node.arguments)
355 visitExpressionList(node.arguments)]) 335 ]).withSourceInformation(node.sourceInformation);
356 .withSourceInformation(node.sourceInformation);
357 } 336 }
358 337
359 @override 338 @override
360 js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) { 339 js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) {
361 registerMethodInvoke(node.selector, node.mask); 340 registerMethodInvoke(node.selector, node.mask);
362 registry.registerUseInterceptor(); 341 registry.registerUseInterceptor();
363 return js.js('#.#(#)', 342 return js.js('#.#(#)', [
364 [glue.getInterceptorLibrary(), 343 glue.getInterceptorLibrary(),
365 glue.registerOneShotInterceptor(node.selector), 344 glue.registerOneShotInterceptor(node.selector),
366 visitExpressionList(node.arguments)]) 345 visitExpressionList(node.arguments)
367 .withSourceInformation(node.sourceInformation); 346 ]).withSourceInformation(node.sourceInformation);
368 } 347 }
369 348
370 @override 349 @override
371 js.Expression visitLiteralList(tree_ir.LiteralList node) { 350 js.Expression visitLiteralList(tree_ir.LiteralList node) {
372 registry.registerInstantiatedClass(glue.listClass); 351 registry.registerInstantiatedClass(glue.listClass);
373 List<js.Expression> entries = visitExpressionList(node.values); 352 List<js.Expression> entries = visitExpressionList(node.values);
374 return new js.ArrayInitializer(entries); 353 return new js.ArrayInitializer(entries);
375 } 354 }
376 355
377 @override 356 @override
378 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) { 357 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
379 return new js.Binary( 358 return new js.Binary(
380 node.operator, 359 node.operator, visitExpression(node.left), visitExpression(node.right));
381 visitExpression(node.left),
382 visitExpression(node.right));
383 } 360 }
384 361
385 @override 362 @override
386 js.Expression visitNot(tree_ir.Not node) { 363 js.Expression visitNot(tree_ir.Not node) {
387 return new js.Prefix("!", visitExpression(node.operand)); 364 return new js.Prefix("!", visitExpression(node.operand));
388 } 365 }
389 366
390 @override 367 @override
391 js.Expression visitThis(tree_ir.This node) { 368 js.Expression visitThis(tree_ir.This node) {
392 return new js.This(); 369 return new js.This();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 if (node.isTypeTest) { 401 if (node.isTypeTest) {
425 return js.js(r'typeof # === "string"', <js.Expression>[value]); 402 return js.js(r'typeof # === "string"', <js.Expression>[value]);
426 } 403 }
427 // TODO(sra): Implement fast cast via calling 'stringTypeCast'. 404 // TODO(sra): Implement fast cast via calling 'stringTypeCast'.
428 } else if (glue.isBoolClass(clazz)) { 405 } else if (glue.isBoolClass(clazz)) {
429 if (node.isTypeTest) { 406 if (node.isTypeTest) {
430 return js.js(r'typeof # === "boolean"', <js.Expression>[value]); 407 return js.js(r'typeof # === "boolean"', <js.Expression>[value]);
431 } 408 }
432 // TODO(sra): Implement fast cast via calling 'boolTypeCast'. 409 // TODO(sra): Implement fast cast via calling 'boolTypeCast'.
433 } else if (node.isTypeTest && 410 } else if (node.isTypeTest &&
434 node.typeArguments.isEmpty && 411 node.typeArguments.isEmpty &&
435 glue.mayGenerateInstanceofCheck(type) && 412 glue.mayGenerateInstanceofCheck(type) &&
436 tryRegisterInstanceofCheck(clazz)) { 413 tryRegisterInstanceofCheck(clazz)) {
437 return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]); 414 return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]);
438 } 415 }
439 416
440 // The helper we use needs the JSArray class to exist, but for some 417 // The helper we use needs the JSArray class to exist, but for some
441 // reason the helper does not cause this dependency to be registered. 418 // reason the helper does not cause this dependency to be registered.
442 // TODO(asgerf): Most programs need List anyway, but we should fix this. 419 // TODO(asgerf): Most programs need List anyway, but we should fix this.
443 registry.registerInstantiatedClass(glue.listClass); 420 registry.registerInstantiatedClass(glue.listClass);
444 421
445 // We use one of the two helpers: 422 // We use one of the two helpers:
446 // 423 //
447 // checkSubtype(value, $isT, typeArgs, $asT) 424 // checkSubtype(value, $isT, typeArgs, $asT)
448 // subtypeCast(value, $isT, typeArgs, $asT) 425 // subtypeCast(value, $isT, typeArgs, $asT)
449 // 426 //
450 // Any of the last two arguments may be null if there are no type 427 // Any of the last two arguments may be null if there are no type
451 // arguments, and/or if no substitution is required. 428 // arguments, and/or if no substitution is required.
452 Element function = node.isTypeTest 429 Element function =
453 ? glue.getCheckSubtype() 430 node.isTypeTest ? glue.getCheckSubtype() : glue.getSubtypeCast();
454 : glue.getSubtypeCast();
455 431
456 js.Expression isT = js.quoteName(glue.getTypeTestTag(type)); 432 js.Expression isT = js.quoteName(glue.getTypeTestTag(type));
457 433
458 js.Expression typeArgumentArray = typeArguments.isNotEmpty 434 js.Expression typeArgumentArray = typeArguments.isNotEmpty
459 ? new js.ArrayInitializer(typeArguments) 435 ? new js.ArrayInitializer(typeArguments)
460 : new js.LiteralNull(); 436 : new js.LiteralNull();
461 437
462 js.Expression asT = glue.hasStrictSubtype(clazz) 438 js.Expression asT = glue.hasStrictSubtype(clazz)
463 ? js.quoteName(glue.getTypeSubstitutionTag(clazz)) 439 ? js.quoteName(glue.getTypeSubstitutionTag(clazz))
464 : new js.LiteralNull(); 440 : new js.LiteralNull();
465 441
466 return buildStaticHelperInvocation( 442 return buildStaticHelperInvocation(
467 function, 443 function, <js.Expression>[value, isT, typeArgumentArray, asT]);
468 <js.Expression>[value, isT, typeArgumentArray, asT]);
469 } else if (type is TypeVariableType || type is FunctionType) { 444 } else if (type is TypeVariableType || type is FunctionType) {
470 registry.registerTypeUse(new TypeUse.isCheck(type)); 445 registry.registerTypeUse(new TypeUse.isCheck(type));
471 446
472 Element function = node.isTypeTest 447 Element function = node.isTypeTest
473 ? glue.getCheckSubtypeOfRuntimeType() 448 ? glue.getCheckSubtypeOfRuntimeType()
474 : glue.getSubtypeOfRuntimeTypeCast(); 449 : glue.getSubtypeOfRuntimeTypeCast();
475 450
476 // The only type argument is the type held in the type variable. 451 // The only type argument is the type held in the type variable.
477 js.Expression typeValue = typeArguments.single; 452 js.Expression typeValue = typeArguments.single;
478 453
479 return buildStaticHelperInvocation( 454 return buildStaticHelperInvocation(
480 function, 455 function, <js.Expression>[value, typeValue]);
481 <js.Expression>[value, typeValue]);
482 } 456 }
483 return giveup(node, 'type check unimplemented for $type.'); 457 return giveup(node, 'type check unimplemented for $type.');
484 } 458 }
485 459
486 @override 460 @override
487 js.Expression visitGetTypeTestProperty(tree_ir.GetTypeTestProperty node) { 461 js.Expression visitGetTypeTestProperty(tree_ir.GetTypeTestProperty node) {
488 js.Expression object = visitExpression(node.object); 462 js.Expression object = visitExpression(node.object);
489 DartType dartType = node.dartType; 463 DartType dartType = node.dartType;
490 assert(dartType.isInterfaceType); 464 assert(dartType.isInterfaceType);
491 registry.registerTypeUse(new TypeUse.isCheck(dartType)); 465 registry.registerTypeUse(new TypeUse.isCheck(dartType));
(...skipping 27 matching lines...) Expand all
519 return '/'; 493 return '/';
520 case BuiltinOperator.NumRemainder: 494 case BuiltinOperator.NumRemainder:
521 return '%'; 495 return '%';
522 default: 496 default:
523 throw 'Not a compoundable operator: $operator'; 497 throw 'Not a compoundable operator: $operator';
524 } 498 }
525 } 499 }
526 500
527 bool isCompoundableBuiltin(tree_ir.Expression exp) { 501 bool isCompoundableBuiltin(tree_ir.Expression exp) {
528 return exp is tree_ir.ApplyBuiltinOperator && 502 return exp is tree_ir.ApplyBuiltinOperator &&
529 exp.arguments.length == 2 && 503 exp.arguments.length == 2 &&
530 isCompoundableOperator(exp.operator); 504 isCompoundableOperator(exp.operator);
531 } 505 }
532 506
533 bool isOneConstant(tree_ir.Expression exp) { 507 bool isOneConstant(tree_ir.Expression exp) {
534 return exp is tree_ir.Constant && exp.value.isOne; 508 return exp is tree_ir.Constant && exp.value.isOne;
535 } 509 }
536 510
537 js.Expression makeAssignment( 511 js.Expression makeAssignment(js.Expression leftHand, tree_ir.Expression value,
538 js.Expression leftHand, 512 {SourceInformation sourceInformation, BuiltinOperator compound}) {
539 tree_ir.Expression value,
540 {SourceInformation sourceInformation,
541 BuiltinOperator compound}) {
542 if (isOneConstant(value)) { 513 if (isOneConstant(value)) {
543 if (compound == BuiltinOperator.NumAdd) { 514 if (compound == BuiltinOperator.NumAdd) {
544 return new js.Prefix('++', leftHand) 515 return new js.Prefix('++', leftHand)
545 .withSourceInformation(sourceInformation); 516 .withSourceInformation(sourceInformation);
546 } 517 }
547 if (compound == BuiltinOperator.NumSubtract) { 518 if (compound == BuiltinOperator.NumSubtract) {
548 return new js.Prefix('--', leftHand) 519 return new js.Prefix('--', leftHand)
549 .withSourceInformation(sourceInformation); 520 .withSourceInformation(sourceInformation);
550 } 521 }
551 } 522 }
552 if (compound != null) { 523 if (compound != null) {
553 return new js.Assignment.compound(leftHand, 524 return new js.Assignment.compound(
554 getAsCompoundOperator(compound), visitExpression(value)) 525 leftHand, getAsCompoundOperator(compound), visitExpression(value))
555 .withSourceInformation(sourceInformation); 526 .withSourceInformation(sourceInformation);
556 } 527 }
557 return new js.Assignment(leftHand, visitExpression(value)) 528 return new js.Assignment(leftHand, visitExpression(value))
558 .withSourceInformation(sourceInformation); 529 .withSourceInformation(sourceInformation);
559 } 530 }
560 531
561 @override 532 @override
562 js.Expression visitAssign(tree_ir.Assign node) { 533 js.Expression visitAssign(tree_ir.Assign node) {
563 js.Expression variable = buildVariableAccess(node.variable); 534 js.Expression variable = buildVariableAccess(node.variable);
564 if (isCompoundableBuiltin(node.value)) { 535 if (isCompoundableBuiltin(node.value)) {
565 tree_ir.ApplyBuiltinOperator rhs = node.value; 536 tree_ir.ApplyBuiltinOperator rhs = node.value;
566 tree_ir.Expression left = rhs.arguments[0]; 537 tree_ir.Expression left = rhs.arguments[0];
567 tree_ir.Expression right = rhs.arguments[1]; 538 tree_ir.Expression right = rhs.arguments[1];
568 if (left is tree_ir.VariableUse && left.variable == node.variable) { 539 if (left is tree_ir.VariableUse && left.variable == node.variable) {
569 return makeAssignment(variable, right, compound: rhs.operator, 540 return makeAssignment(variable, right,
570 sourceInformation: node.sourceInformation); 541 compound: rhs.operator, sourceInformation: node.sourceInformation);
571 } 542 }
572 } 543 }
573 return makeAssignment( 544 return makeAssignment(variable, node.value,
574 variable, node.value, sourceInformation: node.sourceInformation); 545 sourceInformation: node.sourceInformation);
575 } 546 }
576 547
577 @override 548 @override
578 void visitContinue(tree_ir.Continue node) { 549 void visitContinue(tree_ir.Continue node) {
579 tree_ir.Statement next = fallthrough.target; 550 tree_ir.Statement next = fallthrough.target;
580 if (node.target.binding == next || 551 if (node.target.binding == next ||
581 next is tree_ir.Continue && node.target == next.target) { 552 next is tree_ir.Continue && node.target == next.target) {
582 // Fall through to continue target or to equivalent continue. 553 // Fall through to continue target or to equivalent continue.
583 fallthrough.use(); 554 fallthrough.use();
584 } else if (node.target.binding == shortContinue.target) { 555 } else if (node.target.binding == shortContinue.target) {
585 // The target is the immediately enclosing loop. 556 // The target is the immediately enclosing loop.
586 shortContinue.use(); 557 shortContinue.use();
587 accumulator.add(new js.Continue(null)); 558 accumulator.add(new js.Continue(null));
588 } else { 559 } else {
589 accumulator.add(new js.Continue(makeLabel(node.target))); 560 accumulator.add(new js.Continue(makeLabel(node.target)));
590 } 561 }
591 } 562 }
592 563
593 /// True if [other] is the target of [node] or is a [Break] with the same 564 /// True if [other] is the target of [node] or is a [Break] with the same
594 /// target. This means jumping to [other] is equivalent to executing [node]. 565 /// target. This means jumping to [other] is equivalent to executing [node].
595 bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) { 566 bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) {
596 return node.target.binding.next == other || 567 return node.target.binding.next == other ||
597 other is tree_ir.Break && node.target == other.target; 568 other is tree_ir.Break && node.target == other.target;
598 } 569 }
599 570
600 /// True if the given break is equivalent to an unlabeled continue. 571 /// True if the given break is equivalent to an unlabeled continue.
601 bool isShortContinue(tree_ir.Break node) { 572 bool isShortContinue(tree_ir.Break node) {
602 tree_ir.Statement next = node.target.binding.next; 573 tree_ir.Statement next = node.target.binding.next;
603 return next is tree_ir.Continue && 574 return next is tree_ir.Continue &&
604 next.target.binding == shortContinue.target; 575 next.target.binding == shortContinue.target;
605 } 576 }
606 577
607 @override 578 @override
608 void visitBreak(tree_ir.Break node) { 579 void visitBreak(tree_ir.Break node) {
609 if (isEffectiveBreakTarget(node, fallthrough.target)) { 580 if (isEffectiveBreakTarget(node, fallthrough.target)) {
610 // Fall through to break target or to equivalent break. 581 // Fall through to break target or to equivalent break.
611 fallthrough.use(); 582 fallthrough.use();
612 } else if (isEffectiveBreakTarget(node, shortBreak.target)) { 583 } else if (isEffectiveBreakTarget(node, shortBreak.target)) {
613 // Unlabeled break to the break target or to an equivalent break. 584 // Unlabeled break to the break target or to an equivalent break.
614 shortBreak.use(); 585 shortBreak.use();
615 accumulator.add(new js.Break(null)); 586 accumulator.add(new js.Break(null));
616 } else if (isShortContinue(node)) { 587 } else if (isShortContinue(node)) {
617 // An unlabeled continue is better than a labeled break. 588 // An unlabeled continue is better than a labeled break.
618 shortContinue.use(); 589 shortContinue.use();
619 accumulator.add(new js.Continue(null)); 590 accumulator.add(new js.Continue(null));
620 } else { 591 } else {
621 accumulator.add(new js.Break(makeLabel(node.target))); 592 accumulator.add(new js.Break(makeLabel(node.target)));
622 } 593 }
623 } 594 }
624 595
625 @override 596 @override
626 visitExpressionStatement(tree_ir.ExpressionStatement node) { 597 visitExpressionStatement(tree_ir.ExpressionStatement node) {
627 js.Expression exp = visitExpression(node.expression); 598 js.Expression exp = visitExpression(node.expression);
628 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) { 599 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
629 // Emit as 'return exp' to assist local analysis in the VM. 600 // Emit as 'return exp' to assist local analysis in the VM.
630 SourceInformation sourceInformation = node.expression.sourceInformation; 601 SourceInformation sourceInformation = node.expression.sourceInformation;
631 accumulator.add( 602 accumulator
632 new js.Return(exp).withSourceInformation(sourceInformation)); 603 .add(new js.Return(exp).withSourceInformation(sourceInformation));
633 return null; 604 return null;
634 } else { 605 } else {
635 accumulator.add(new js.ExpressionStatement(exp)); 606 accumulator.add(new js.ExpressionStatement(exp));
636 return node.next; 607 return node.next;
637 } 608 }
638 } 609 }
639 610
640 bool isNullReturn(tree_ir.Statement node) { 611 bool isNullReturn(tree_ir.Statement node) {
641 return node is tree_ir.Return && isNull(node.value); 612 return node is tree_ir.Return && isNull(node.value);
642 } 613 }
643 614
644 bool isEndOfMethod(tree_ir.Statement node) { 615 bool isEndOfMethod(tree_ir.Statement node) {
645 return isNullReturn(node) || 616 return isNullReturn(node) ||
646 node is tree_ir.Break && isNullReturn(node.target.binding.next); 617 node is tree_ir.Break && isNullReturn(node.target.binding.next);
647 } 618 }
648 619
649 @override 620 @override
650 visitIf(tree_ir.If node) { 621 visitIf(tree_ir.If node) {
651 js.Expression condition = visitExpression(node.condition); 622 js.Expression condition = visitExpression(node.condition);
652 int usesBefore = fallthrough.useCount; 623 int usesBefore = fallthrough.useCount;
653 // Unless the 'else' part ends the method. make sure to terminate any 624 // Unless the 'else' part ends the method. make sure to terminate any
654 // uncompletable code paths in the 'then' part. 625 // uncompletable code paths in the 'then' part.
655 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement)); 626 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
656 js.Statement thenBody = buildBodyStatement(node.thenStatement); 627 js.Statement thenBody = buildBodyStatement(node.thenStatement);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 accumulator = <js.Statement>[]; 692 accumulator = <js.Statement>[];
722 while (statement != null) { 693 while (statement != null) {
723 statement = visitStatement(statement); 694 statement = visitStatement(statement);
724 } 695 }
725 js.Statement result = new js.Block(accumulator); 696 js.Statement result = new js.Block(accumulator);
726 accumulator = savedAccumulator; 697 accumulator = savedAccumulator;
727 return result; 698 return result;
728 } 699 }
729 700
730 js.Expression makeSequence(List<tree_ir.Expression> list) { 701 js.Expression makeSequence(List<tree_ir.Expression> list) {
731 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y)); 702 return list.map(visitExpression).reduce((x, y) => new js.Binary(',', x, y));
732 } 703 }
733 704
734 @override 705 @override
735 visitFor(tree_ir.For node) { 706 visitFor(tree_ir.For node) {
736 js.Expression condition = visitExpression(node.condition); 707 js.Expression condition = visitExpression(node.condition);
737 shortBreak.push(node.next); 708 shortBreak.push(node.next);
738 shortContinue.push(node); 709 shortContinue.push(node);
739 fallthrough.push(node); 710 fallthrough.push(node);
740 emitUnreachableAsReturn.add(true); 711 emitUnreachableAsReturn.add(true);
741 js.Statement body = buildBodyStatement(node.body); 712 js.Statement body = buildBodyStatement(node.body);
742 emitUnreachableAsReturn.removeLast(); 713 emitUnreachableAsReturn.removeLast();
743 fallthrough.pop(); 714 fallthrough.pop();
744 shortContinue.pop(); 715 shortContinue.pop();
745 shortBreak.pop(); 716 shortBreak.pop();
746 js.Statement loopNode; 717 js.Statement loopNode;
747 if (node.updates.isEmpty) { 718 if (node.updates.isEmpty) {
748 loopNode = new js.While(condition, body); 719 loopNode = new js.While(condition, body);
749 } else { // Compile as a for loop. 720 } else {
721 // Compile as a for loop.
750 js.Expression init; 722 js.Expression init;
751 if (accumulator.isNotEmpty && 723 if (accumulator.isNotEmpty &&
752 accumulator.last is js.ExpressionStatement) { 724 accumulator.last is js.ExpressionStatement) {
753 // Take the preceding expression from the accumulator and use 725 // Take the preceding expression from the accumulator and use
754 // it as the initializer expression. 726 // it as the initializer expression.
755 js.ExpressionStatement initStmt = accumulator.removeLast(); 727 js.ExpressionStatement initStmt = accumulator.removeLast();
756 init = initStmt.expression; 728 init = initStmt.expression;
757 } 729 }
758 js.Expression update = makeSequence(node.updates); 730 js.Expression update = makeSequence(node.updates);
759 loopNode = new js.For(init, condition, update, body); 731 loopNode = new js.For(init, condition, update, body);
(...skipping 11 matching lines...) Expand all
771 emitUnreachableAsReturn.add(true); 743 emitUnreachableAsReturn.add(true);
772 js.Statement jsBody = buildBodyStatement(node.body); 744 js.Statement jsBody = buildBodyStatement(node.body);
773 emitUnreachableAsReturn.removeLast(); 745 emitUnreachableAsReturn.removeLast();
774 fallthrough.pop(); 746 fallthrough.pop();
775 shortContinue.pop(); 747 shortContinue.pop();
776 if (shortBreak.useCount > 0) { 748 if (shortBreak.useCount > 0) {
777 // Short breaks use the current fallthrough target. 749 // Short breaks use the current fallthrough target.
778 fallthrough.use(); 750 fallthrough.use();
779 } 751 }
780 shortBreak.pop(); 752 shortBreak.pop();
781 accumulator.add( 753 accumulator
782 insertLabel(node.label, new js.For(null, null, null, jsBody))); 754 .add(insertLabel(node.label, new js.For(null, null, null, jsBody)));
783 } 755 }
784 756
785 bool isNull(tree_ir.Expression node) { 757 bool isNull(tree_ir.Expression node) {
786 return node is tree_ir.Constant && node.value.isNull; 758 return node is tree_ir.Constant && node.value.isNull;
787 } 759 }
788 760
789 @override 761 @override
790 void visitReturn(tree_ir.Return node) { 762 void visitReturn(tree_ir.Return node) {
791 if (isNull(node.value) && fallthrough.target == null) { 763 if (isNull(node.value) && fallthrough.target == null) {
792 // Do nothing. Implicitly return JS undefined by falling over the end. 764 // Do nothing. Implicitly return JS undefined by falling over the end.
793 registry.registerCompileTimeConstant(new NullConstantValue()); 765 registry.registerCompileTimeConstant(new NullConstantValue());
794 fallthrough.use(); 766 fallthrough.use();
795 } else { 767 } else {
796 accumulator.add(new js.Return(visitExpression(node.value)) 768 accumulator.add(new js.Return(visitExpression(node.value))
797 .withSourceInformation(node.sourceInformation)); 769 .withSourceInformation(node.sourceInformation));
798 } 770 }
799 } 771 }
800 772
801 @override 773 @override
802 void visitThrow(tree_ir.Throw node) { 774 void visitThrow(tree_ir.Throw node) {
803 accumulator.add(new js.Throw(visitExpression(node.value))); 775 accumulator.add(new js.Throw(visitExpression(node.value)));
804 } 776 }
805 777
806 @override 778 @override
807 void visitUnreachable(tree_ir.Unreachable node) { 779 void visitUnreachable(tree_ir.Unreachable node) {
(...skipping 23 matching lines...) Expand all
831 js.Expression visitCreateInstance(tree_ir.CreateInstance node) { 803 js.Expression visitCreateInstance(tree_ir.CreateInstance node) {
832 ClassElement classElement = node.classElement; 804 ClassElement classElement = node.classElement;
833 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must 805 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must
834 // carry a DartType so we can register the instantiated type 806 // carry a DartType so we can register the instantiated type
835 // with its type arguments. Otherwise dataflow analysis is 807 // with its type arguments. Otherwise dataflow analysis is
836 // needed to reconstruct the instantiated type. 808 // needed to reconstruct the instantiated type.
837 registry.registerInstantiation(classElement.rawType); 809 registry.registerInstantiation(classElement.rawType);
838 if (classElement is ClosureClassElement) { 810 if (classElement is ClosureClassElement) {
839 registry.registerInstantiatedClosure(classElement.methodElement); 811 registry.registerInstantiatedClosure(classElement.methodElement);
840 } 812 }
841 js.Expression instance = new js.New( 813 js.Expression instance = new js.New(glue.constructorAccess(classElement),
842 glue.constructorAccess(classElement),
843 visitExpressionList(node.arguments)) 814 visitExpressionList(node.arguments))
844 .withSourceInformation(node.sourceInformation); 815 .withSourceInformation(node.sourceInformation);
845 816
846 tree_ir.Expression typeInformation = node.typeInformation; 817 tree_ir.Expression typeInformation = node.typeInformation;
847 if (typeInformation != null) { 818 if (typeInformation != null) {
848 FunctionElement helper = glue.getAddRuntimeTypeInformation(); 819 FunctionElement helper = glue.getAddRuntimeTypeInformation();
849 js.Expression typeArguments = visitExpression(typeInformation); 820 js.Expression typeArguments = visitExpression(typeInformation);
850 return buildStaticHelperInvocation(helper, 821 return buildStaticHelperInvocation(
851 <js.Expression>[instance, typeArguments], 822 helper, <js.Expression>[instance, typeArguments],
852 sourceInformation: node.sourceInformation); 823 sourceInformation: node.sourceInformation);
853 } else { 824 } else {
854 return instance; 825 return instance;
855 } 826 }
856 } 827 }
857 828
858 @override 829 @override
859 js.Expression visitCreateInvocationMirror( 830 js.Expression visitCreateInvocationMirror(
860 tree_ir.CreateInvocationMirror node) { 831 tree_ir.CreateInvocationMirror node) {
861 js.Expression name = js.string(node.selector.name); 832 js.Expression name = js.string(node.selector.name);
862 js.Expression internalName = 833 js.Expression internalName =
863 js.quoteName(glue.invocationName(node.selector)); 834 js.quoteName(glue.invocationName(node.selector));
864 js.Expression kind = js.number(node.selector.invocationMirrorKind); 835 js.Expression kind = js.number(node.selector.invocationMirrorKind);
865 js.Expression arguments = new js.ArrayInitializer( 836 js.Expression arguments =
866 visitExpressionList(node.arguments)); 837 new js.ArrayInitializer(visitExpressionList(node.arguments));
867 js.Expression argumentNames = new js.ArrayInitializer( 838 js.Expression argumentNames = new js.ArrayInitializer(
868 node.selector.namedArguments.map(js.string).toList(growable: false)); 839 node.selector.namedArguments.map(js.string).toList(growable: false));
869 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod, 840 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod,
870 <js.Expression>[name, internalName, kind, arguments, argumentNames]); 841 <js.Expression>[name, internalName, kind, arguments, argumentNames]);
871 } 842 }
872 843
873 @override 844 @override
874 js.Expression visitInterceptor(tree_ir.Interceptor node) { 845 js.Expression visitInterceptor(tree_ir.Interceptor node) {
875 registry.registerUseInterceptor(); 846 registry.registerUseInterceptor();
876 // Default to all intercepted classes if they have not been computed. 847 // Default to all intercepted classes if they have not been computed.
877 // This is to ensure we can run codegen without prior optimization passes. 848 // This is to ensure we can run codegen without prior optimization passes.
878 Set<ClassElement> interceptedClasses = node.interceptedClasses.isEmpty 849 Set<ClassElement> interceptedClasses = node.interceptedClasses.isEmpty
879 ? glue.interceptedClasses 850 ? glue.interceptedClasses
880 : node.interceptedClasses; 851 : node.interceptedClasses;
881 registry.registerSpecializedGetInterceptor(interceptedClasses); 852 registry.registerSpecializedGetInterceptor(interceptedClasses);
882 js.Name helperName = glue.getInterceptorName(interceptedClasses); 853 js.Name helperName = glue.getInterceptorName(interceptedClasses);
883 js.Expression globalHolder = glue.getInterceptorLibrary(); 854 js.Expression globalHolder = glue.getInterceptorLibrary();
884 return js.js('#.#(#)', 855 return js.js('#.#(#)', [
885 [globalHolder, helperName, visitExpression(node.input)]) 856 globalHolder,
886 .withSourceInformation(node.sourceInformation); 857 helperName,
858 visitExpression(node.input)
859 ]).withSourceInformation(node.sourceInformation);
887 } 860 }
888 861
889 @override 862 @override
890 js.Expression visitGetField(tree_ir.GetField node) { 863 js.Expression visitGetField(tree_ir.GetField node) {
891 registry.registerStaticUse(new StaticUse.fieldGet(node.field)); 864 registry.registerStaticUse(new StaticUse.fieldGet(node.field));
892 return new js.PropertyAccess( 865 return new js.PropertyAccess(visitExpression(node.object),
893 visitExpression(node.object), 866 glue.instanceFieldPropertyName(node.field))
894 glue.instanceFieldPropertyName(node.field))
895 .withSourceInformation(node.sourceInformation); 867 .withSourceInformation(node.sourceInformation);
896 } 868 }
897 869
898 @override 870 @override
899 js.Expression visitSetField(tree_ir.SetField node) { 871 js.Expression visitSetField(tree_ir.SetField node) {
900 registry.registerStaticUse(new StaticUse.fieldSet(node.field)); 872 registry.registerStaticUse(new StaticUse.fieldSet(node.field));
901 js.PropertyAccess field = 873 js.PropertyAccess field = new js.PropertyAccess(
902 new js.PropertyAccess( 874 visitExpression(node.object),
903 visitExpression(node.object), 875 glue.instanceFieldPropertyName(node.field));
904 glue.instanceFieldPropertyName(node.field)); 876 return makeAssignment(field, node.value,
905 return makeAssignment(field, node.value, compound: node.compound, 877 compound: node.compound, sourceInformation: node.sourceInformation);
906 sourceInformation: node.sourceInformation);
907 } 878 }
908 879
909 @override 880 @override
910 js.Expression visitGetStatic(tree_ir.GetStatic node) { 881 js.Expression visitGetStatic(tree_ir.GetStatic node) {
911 assert(node.element is FieldElement || node.element is FunctionElement); 882 assert(node.element is FieldElement || node.element is FunctionElement);
912 if (node.element is FunctionElement) { 883 if (node.element is FunctionElement) {
913 // Tear off a method. 884 // Tear off a method.
914 registry.registerStaticUse( 885 registry.registerStaticUse(
915 new StaticUse.staticTearOff(node.element.declaration)); 886 new StaticUse.staticTearOff(node.element.declaration));
916 return glue.isolateStaticClosureAccess(node.element) 887 return glue
917 .withSourceInformation(node.sourceInformation); 888 .isolateStaticClosureAccess(node.element)
889 .withSourceInformation(node.sourceInformation);
918 } 890 }
919 if (node.useLazyGetter) { 891 if (node.useLazyGetter) {
920 // Read a lazily initialized field. 892 // Read a lazily initialized field.
921 registry.registerStaticUse( 893 registry.registerStaticUse(
922 new StaticUse.staticInit(node.element.declaration)); 894 new StaticUse.staticInit(node.element.declaration));
923 js.Expression getter = glue.isolateLazyInitializerAccess(node.element); 895 js.Expression getter = glue.isolateLazyInitializerAccess(node.element);
924 return new js.Call(getter, <js.Expression>[], 896 return new js.Call(getter, <js.Expression>[],
925 sourceInformation: node.sourceInformation); 897 sourceInformation: node.sourceInformation);
926 } 898 }
927 // Read an eagerly initialized field. 899 // Read an eagerly initialized field.
928 registry.registerStaticUse( 900 registry
929 new StaticUse.staticGet(node.element.declaration)); 901 .registerStaticUse(new StaticUse.staticGet(node.element.declaration));
930 return glue.staticFieldAccess(node.element) 902 return glue
903 .staticFieldAccess(node.element)
931 .withSourceInformation(node.sourceInformation); 904 .withSourceInformation(node.sourceInformation);
932 } 905 }
933 906
934 @override 907 @override
935 js.Expression visitSetStatic(tree_ir.SetStatic node) { 908 js.Expression visitSetStatic(tree_ir.SetStatic node) {
936 assert(node.element is FieldElement); 909 assert(node.element is FieldElement);
937 registry.registerStaticUse( 910 registry
938 new StaticUse.staticSet(node.element.declaration)); 911 .registerStaticUse(new StaticUse.staticSet(node.element.declaration));
939 js.Expression field = glue.staticFieldAccess(node.element); 912 js.Expression field = glue.staticFieldAccess(node.element);
940 return makeAssignment(field, node.value, compound: node.compound, 913 return makeAssignment(field, node.value,
941 sourceInformation: node.sourceInformation); 914 compound: node.compound, sourceInformation: node.sourceInformation);
942 } 915 }
943 916
944 @override 917 @override
945 js.Expression visitGetLength(tree_ir.GetLength node) { 918 js.Expression visitGetLength(tree_ir.GetLength node) {
946 return new js.PropertyAccess.field(visitExpression(node.object), 'length'); 919 return new js.PropertyAccess.field(visitExpression(node.object), 'length');
947 } 920 }
948 921
949 @override 922 @override
950 js.Expression visitGetIndex(tree_ir.GetIndex node) { 923 js.Expression visitGetIndex(tree_ir.GetIndex node) {
951 return new js.PropertyAccess( 924 return new js.PropertyAccess(
952 visitExpression(node.object), 925 visitExpression(node.object), visitExpression(node.index));
953 visitExpression(node.index));
954 } 926 }
955 927
956 @override 928 @override
957 js.Expression visitSetIndex(tree_ir.SetIndex node) { 929 js.Expression visitSetIndex(tree_ir.SetIndex node) {
958 js.Expression index = new js.PropertyAccess( 930 js.Expression index = new js.PropertyAccess(
959 visitExpression(node.object), visitExpression(node.index)); 931 visitExpression(node.object), visitExpression(node.index));
960 return makeAssignment(index, node.value, compound: node.compound); 932 return makeAssignment(index, node.value, compound: node.compound);
961 } 933 }
962 934
963 js.Expression buildStaticHelperInvocation( 935 js.Expression buildStaticHelperInvocation(
964 FunctionElement helper, 936 FunctionElement helper, List<js.Expression> arguments,
965 List<js.Expression> arguments,
966 {SourceInformation sourceInformation}) { 937 {SourceInformation sourceInformation}) {
967 registry.registerStaticUse(new StaticUse.staticInvoke( 938 registry.registerStaticUse(new StaticUse.staticInvoke(
968 helper, new CallStructure.unnamed(arguments.length))); 939 helper, new CallStructure.unnamed(arguments.length)));
969 return buildStaticInvoke( 940 return buildStaticInvoke(helper, arguments,
970 helper, arguments, sourceInformation: sourceInformation); 941 sourceInformation: sourceInformation);
971 } 942 }
972 943
973 @override 944 @override
974 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) { 945 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) {
975 js.Expression typeToString = buildStaticHelperInvocation( 946 js.Expression typeToString = buildStaticHelperInvocation(
976 glue.getRuntimeTypeToString(), 947 glue.getRuntimeTypeToString(), [visitExpression(node.value)],
977 [visitExpression(node.value)],
978 sourceInformation: node.sourceInformation); 948 sourceInformation: node.sourceInformation);
979 return buildStaticHelperInvocation( 949 return buildStaticHelperInvocation(
980 glue.getCreateRuntimeType(), 950 glue.getCreateRuntimeType(), [typeToString],
981 [typeToString],
982 sourceInformation: node.sourceInformation); 951 sourceInformation: node.sourceInformation);
983 } 952 }
984 953
985 @override 954 @override
986 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) { 955 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) {
987 ClassElement context = node.variable.element.enclosingClass; 956 ClassElement context = node.variable.element.enclosingClass;
988 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable)); 957 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable));
989 if (glue.needsSubstitutionForTypeVariableAccess(context)) { 958 if (glue.needsSubstitutionForTypeVariableAccess(context)) {
990 js.Expression typeName = glue.getRuntimeTypeName(context); 959 js.Expression typeName = glue.getRuntimeTypeName(context);
991 return buildStaticHelperInvocation( 960 return buildStaticHelperInvocation(glue.getRuntimeTypeArgument(),
992 glue.getRuntimeTypeArgument(),
993 [visitExpression(node.target), typeName, index], 961 [visitExpression(node.target), typeName, index],
994 sourceInformation: node.sourceInformation); 962 sourceInformation: node.sourceInformation);
995 } else { 963 } else {
996 return buildStaticHelperInvocation( 964 return buildStaticHelperInvocation(
997 glue.getTypeArgumentByIndex(), 965 glue.getTypeArgumentByIndex(), [visitExpression(node.target), index],
998 [visitExpression(node.target), index],
999 sourceInformation: node.sourceInformation); 966 sourceInformation: node.sourceInformation);
1000 } 967 }
1001 } 968 }
1002 969
1003 @override 970 @override
1004 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { 971 js.Expression visitTypeExpression(tree_ir.TypeExpression node) {
1005 List<js.Expression> arguments = visitExpressionList(node.arguments); 972 List<js.Expression> arguments = visitExpressionList(node.arguments);
1006 switch (node.kind) { 973 switch (node.kind) {
1007 case tree_ir.TypeExpressionKind.COMPLETE: 974 case tree_ir.TypeExpressionKind.COMPLETE:
1008 return glue.generateTypeRepresentation( 975 return glue.generateTypeRepresentation(
1009 node.dartType, arguments, registry); 976 node.dartType, arguments, registry);
1010 case tree_ir.TypeExpressionKind.INSTANCE: 977 case tree_ir.TypeExpressionKind.INSTANCE:
1011 // We expect only flat types for the INSTANCE representation. 978 // We expect only flat types for the INSTANCE representation.
1012 assert(node.dartType == 979 assert(
1013 (node.dartType.element as ClassElement).thisType); 980 node.dartType == (node.dartType.element as ClassElement).thisType);
1014 registry.registerInstantiatedClass(glue.listClass); 981 registry.registerInstantiatedClass(glue.listClass);
1015 return new js.ArrayInitializer(arguments); 982 return new js.ArrayInitializer(arguments);
1016 } 983 }
1017 } 984 }
1018 985
1019 js.Node handleForeignCode(tree_ir.ForeignCode node) { 986 js.Node handleForeignCode(tree_ir.ForeignCode node) {
1020 if (node.dependency != null) { 987 if (node.dependency != null) {
1021 // Dependency is only used if [node] calls a Dart function. Currently only 988 // Dependency is only used if [node] calls a Dart function. Currently only
1022 // through foreign function `RAW_DART_FUNCTION_REF`. 989 // through foreign function `RAW_DART_FUNCTION_REF`.
1023 registry.registerStaticUse( 990 registry.registerStaticUse(new StaticUse.staticInvoke(
1024 new StaticUse.staticInvoke( 991 node.dependency, new CallStructure.unnamed(node.arguments.length)));
1025 node.dependency,
1026 new CallStructure.unnamed(node.arguments.length)));
1027 } 992 }
1028 // TODO(sra,johnniwinther): Should this be in CodegenRegistry? 993 // TODO(sra,johnniwinther): Should this be in CodegenRegistry?
1029 glue.registerNativeBehavior(node.nativeBehavior, node); 994 glue.registerNativeBehavior(node.nativeBehavior, node);
1030 return node.codeTemplate.instantiate(visitExpressionList(node.arguments)) 995 return node.codeTemplate
996 .instantiate(visitExpressionList(node.arguments))
1031 .withSourceInformation(node.sourceInformation); 997 .withSourceInformation(node.sourceInformation);
1032 } 998 }
1033 999
1034 @override 1000 @override
1035 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) { 1001 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) {
1036 return handleForeignCode(node); 1002 return handleForeignCode(node);
1037 } 1003 }
1038 1004
1039 @override 1005 @override
1040 void visitForeignStatement(tree_ir.ForeignStatement node) { 1006 void visitForeignStatement(tree_ir.ForeignStatement node) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1113 return normalizeBitOp(js.js('# << #', args), node); 1079 return normalizeBitOp(js.js('# << #', args), node);
1114 case BuiltinOperator.NumShr: 1080 case BuiltinOperator.NumShr:
1115 // No normalization required since output is always uint32. 1081 // No normalization required since output is always uint32.
1116 return js.js('# >>> #', args); 1082 return js.js('# >>> #', args);
1117 case BuiltinOperator.NumBitNot: 1083 case BuiltinOperator.NumBitNot:
1118 return js.js('(~#) >>> 0', args); 1084 return js.js('(~#) >>> 0', args);
1119 case BuiltinOperator.NumNegate: 1085 case BuiltinOperator.NumNegate:
1120 return js.js('-#', args); 1086 return js.js('-#', args);
1121 case BuiltinOperator.StringConcatenate: 1087 case BuiltinOperator.StringConcatenate:
1122 if (args.isEmpty) return js.string(''); 1088 if (args.isEmpty) return js.string('');
1123 return args.reduce((e1,e2) => new js.Binary('+', e1, e2)); 1089 return args.reduce((e1, e2) => new js.Binary('+', e1, e2));
1124 case BuiltinOperator.CharCodeAt: 1090 case BuiltinOperator.CharCodeAt:
1125 return js.js('#.charCodeAt(#)', args); 1091 return js.js('#.charCodeAt(#)', args);
1126 case BuiltinOperator.Identical: 1092 case BuiltinOperator.Identical:
1127 registry.registerStaticUse(new StaticUse.staticInvoke( 1093 registry.registerStaticUse(new StaticUse.staticInvoke(
1128 glue.identicalFunction, new CallStructure.unnamed(args.length))); 1094 glue.identicalFunction, new CallStructure.unnamed(args.length)));
1129 return buildStaticHelperInvocation(glue.identicalFunction, args); 1095 return buildStaticHelperInvocation(glue.identicalFunction, args);
1130 case BuiltinOperator.StrictEq: 1096 case BuiltinOperator.StrictEq:
1131 return new js.Binary('===', args[0], args[1]); 1097 return new js.Binary('===', args[0], args[1]);
1132 case BuiltinOperator.StrictNeq: 1098 case BuiltinOperator.StrictNeq:
1133 return new js.Binary('!==', args[0], args[1]); 1099 return new js.Binary('!==', args[0], args[1]);
(...skipping 28 matching lines...) Expand all
1162 // TODO(sra): Remove boolify (i.e. !!). 1128 // TODO(sra): Remove boolify (i.e. !!).
1163 return js.js(r'!!#.immutable$list', args); 1129 return js.js(r'!!#.immutable$list', args);
1164 } 1130 }
1165 } 1131 }
1166 1132
1167 return createExpression().withSourceInformation(node.sourceInformation); 1133 return createExpression().withSourceInformation(node.sourceInformation);
1168 } 1134 }
1169 1135
1170 /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit 1136 /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit
1171 /// range. 1137 /// range.
1172 js.Expression normalizeBitOp(js.Expression op, 1138 js.Expression normalizeBitOp(
1173 tree_ir.ApplyBuiltinOperator node) { 1139 js.Expression op, tree_ir.ApplyBuiltinOperator node) {
1174 const MAX_UINT31 = 0x7fffffff; 1140 const MAX_UINT31 = 0x7fffffff;
1175 const MAX_UINT32 = 0xffffffff; 1141 const MAX_UINT32 = 0xffffffff;
1176 1142
1177 int constantValue(tree_ir.Expression e) { 1143 int constantValue(tree_ir.Expression e) {
1178 if (e is tree_ir.Constant) { 1144 if (e is tree_ir.Constant) {
1179 ConstantValue value = e.value; 1145 ConstantValue value = e.value;
1180 if (!value.isInt) return null; 1146 if (!value.isInt) return null;
1181 IntConstantValue intConstant = value; 1147 IntConstantValue intConstant = value;
1182 if (intConstant.primitiveValue < 0) return null; 1148 if (intConstant.primitiveValue < 0) return null;
1183 if (intConstant.primitiveValue > MAX_UINT32) return null; 1149 if (intConstant.primitiveValue > MAX_UINT32) return null;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1266 void registerDefaultParameterValues(ExecutableElement element) { 1232 void registerDefaultParameterValues(ExecutableElement element) {
1267 if (element is! FunctionElement) return; 1233 if (element is! FunctionElement) return;
1268 FunctionElement function = element; 1234 FunctionElement function = element;
1269 if (function.isStatic) return; // Defaults are inlined at call sites. 1235 if (function.isStatic) return; // Defaults are inlined at call sites.
1270 function.functionSignature.forEachOptionalParameter((param) { 1236 function.functionSignature.forEachOptionalParameter((param) {
1271 ConstantValue constant = glue.getDefaultParameterValue(param); 1237 ConstantValue constant = glue.getDefaultParameterValue(param);
1272 registry.registerCompileTimeConstant(constant); 1238 registry.registerCompileTimeConstant(constant);
1273 }); 1239 });
1274 } 1240 }
1275 } 1241 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/glue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698