OLD | NEW |
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 |
10 ClosureClassElement; | 10 ClosureClassElement; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 | 274 |
275 registry.registerInstantiation(node.type); | 275 registry.registerInstantiation(node.type); |
276 FunctionElement target = node.target; | 276 FunctionElement target = node.target; |
277 List<js.Expression> arguments = visitExpressionList(node.arguments); | 277 List<js.Expression> arguments = visitExpressionList(node.arguments); |
278 return buildStaticInvoke( | 278 return buildStaticInvoke( |
279 target, | 279 target, |
280 arguments, | 280 arguments, |
281 sourceInformation: node.sourceInformation); | 281 sourceInformation: node.sourceInformation); |
282 } | 282 } |
283 | 283 |
284 void registerMethodInvoke(tree_ir.InvokeMethod node) { | 284 void registerMethodInvoke(Selector selector, TypeMask receiverType) { |
285 Selector selector = node.selector; | 285 registry.registerDynamicUse(new DynamicUse(selector, receiverType)); |
286 TypeMask mask = node.mask; | 286 if (!selector.isGetter && !selector.isSetter) { |
287 mask = glue.extendMaskIfReachesAll(selector, mask); | |
288 if (selector.isGetter) { | |
289 registry.registerDynamicUse(new DynamicUse(selector, mask)); | |
290 } else if (selector.isSetter) { | |
291 registry.registerDynamicUse(new DynamicUse(selector, mask)); | |
292 } else { | |
293 assert(invariant(CURRENT_ELEMENT_SPANNABLE, | |
294 selector.isCall || selector.isOperator || | |
295 selector.isIndex || selector.isIndexSet, | |
296 message: 'unexpected kind ${selector.kind}')); | |
297 // TODO(sigurdm): We should find a better place to register the call. | 287 // TODO(sigurdm): We should find a better place to register the call. |
298 Selector call = new Selector.callClosureFrom(selector); | 288 Selector call = new Selector.callClosureFrom(selector); |
299 registry.registerDynamicUse(new DynamicUse(call, null)); | 289 registry.registerDynamicUse(new DynamicUse(call, null)); |
300 registry.registerDynamicUse(new DynamicUse(selector, mask)); | |
301 } | 290 } |
302 } | 291 } |
303 | 292 |
304 @override | 293 @override |
305 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { | 294 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { |
306 registerMethodInvoke(node); | 295 TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask); |
| 296 registerMethodInvoke(node.selector, mask); |
307 return js.propertyCall(visitExpression(node.receiver), | 297 return js.propertyCall(visitExpression(node.receiver), |
308 glue.invocationName(node.selector), | 298 glue.invocationName(node.selector), |
309 visitExpressionList(node.arguments)) | 299 visitExpressionList(node.arguments)) |
310 .withSourceInformation(node.sourceInformation); | 300 .withSourceInformation(node.sourceInformation); |
311 } | 301 } |
312 | 302 |
313 @override | 303 @override |
314 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { | 304 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { |
315 FunctionElement target = node.target; | 305 FunctionElement target = node.target; |
316 List<js.Expression> arguments = visitExpressionList(node.arguments); | 306 List<js.Expression> arguments = visitExpressionList(node.arguments); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 new CallStructure.unnamed(node.arguments.length))); | 338 new CallStructure.unnamed(node.arguments.length))); |
349 return js.js('#.#.call(#, #)', | 339 return js.js('#.#.call(#, #)', |
350 [glue.prototypeAccess(node.target.enclosingClass), | 340 [glue.prototypeAccess(node.target.enclosingClass), |
351 glue.invocationName(node.selector), | 341 glue.invocationName(node.selector), |
352 visitExpression(node.receiver), | 342 visitExpression(node.receiver), |
353 visitExpressionList(node.arguments)]) | 343 visitExpressionList(node.arguments)]) |
354 .withSourceInformation(node.sourceInformation); | 344 .withSourceInformation(node.sourceInformation); |
355 } | 345 } |
356 | 346 |
357 @override | 347 @override |
| 348 js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) { |
| 349 registerMethodInvoke(node.selector, node.mask); |
| 350 registry.registerUseInterceptor(); |
| 351 return js.js('#.#(#)', |
| 352 [glue.getInterceptorLibrary(), |
| 353 glue.registerOneShotInterceptor(node.selector), |
| 354 visitExpressionList(node.arguments)]) |
| 355 .withSourceInformation(node.sourceInformation); |
| 356 } |
| 357 |
| 358 @override |
358 js.Expression visitLiteralList(tree_ir.LiteralList node) { | 359 js.Expression visitLiteralList(tree_ir.LiteralList node) { |
359 registry.registerInstantiatedClass(glue.listClass); | 360 registry.registerInstantiatedClass(glue.listClass); |
360 List<js.Expression> entries = visitExpressionList(node.values); | 361 List<js.Expression> entries = visitExpressionList(node.values); |
361 return new js.ArrayInitializer(entries); | 362 return new js.ArrayInitializer(entries); |
362 } | 363 } |
363 | 364 |
364 @override | 365 @override |
365 js.Expression visitLiteralMap(tree_ir.LiteralMap node) { | 366 js.Expression visitLiteralMap(tree_ir.LiteralMap node) { |
366 ConstructorElement constructor; | 367 ConstructorElement constructor; |
367 if (node.entries.isEmpty) { | 368 if (node.entries.isEmpty) { |
(...skipping 24 matching lines...) Expand all Loading... |
392 @override | 393 @override |
393 js.Expression visitNot(tree_ir.Not node) { | 394 js.Expression visitNot(tree_ir.Not node) { |
394 return new js.Prefix("!", visitExpression(node.operand)); | 395 return new js.Prefix("!", visitExpression(node.operand)); |
395 } | 396 } |
396 | 397 |
397 @override | 398 @override |
398 js.Expression visitThis(tree_ir.This node) { | 399 js.Expression visitThis(tree_ir.This node) { |
399 return new js.This(); | 400 return new js.This(); |
400 } | 401 } |
401 | 402 |
| 403 /// Ensure that 'instanceof' checks may be performed against [class_]. |
| 404 /// |
| 405 /// Even if the class is never instantiated, a JS constructor must be emitted |
| 406 /// so the 'instanceof' expression does not throw an exception at runtime. |
| 407 /// |
| 408 /// It does not help to ask the class world if the class is instantiated, |
| 409 /// because it could still get tree-shaken if it is unused after optimization. |
| 410 void registerInstanceofCheck(ClassElement class_) { |
| 411 // TODO(asgerf): This is the only hook we have to ensure the JS constructor |
| 412 // gets emitted, but it is very imprecise. We should do better. |
| 413 registry.registerInstantiatedClass(class_); |
| 414 } |
| 415 |
402 @override | 416 @override |
403 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { | 417 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { |
404 js.Expression value = visitExpression(node.value); | 418 js.Expression value = visitExpression(node.value); |
405 List<js.Expression> typeArguments = visitExpressionList(node.typeArguments); | 419 List<js.Expression> typeArguments = visitExpressionList(node.typeArguments); |
406 DartType type = node.type; | 420 DartType type = node.type; |
407 if (type is InterfaceType) { | 421 if (type is InterfaceType) { |
408 registry.registerTypeUse(new TypeUse.isCheck(type)); | 422 registry.registerTypeUse(new TypeUse.isCheck(type)); |
409 //glue.registerIsCheck(type, registry); | |
410 ClassElement clazz = type.element; | 423 ClassElement clazz = type.element; |
411 | 424 |
412 if (glue.isStringClass(clazz)) { | 425 if (glue.isStringClass(clazz)) { |
413 if (node.isTypeTest) { | 426 if (node.isTypeTest) { |
414 return js.js(r'typeof # === "string"', <js.Expression>[value]); | 427 return js.js(r'typeof # === "string"', <js.Expression>[value]); |
415 } | 428 } |
416 // TODO(sra): Implement fast cast via calling 'stringTypeCast'. | 429 // TODO(sra): Implement fast cast via calling 'stringTypeCast'. |
417 } else if (glue.isBoolClass(clazz)) { | 430 } else if (glue.isBoolClass(clazz)) { |
418 if (node.isTypeTest) { | 431 if (node.isTypeTest) { |
419 return js.js(r'typeof # === "boolean"', <js.Expression>[value]); | 432 return js.js(r'typeof # === "boolean"', <js.Expression>[value]); |
420 } | 433 } |
421 // TODO(sra): Implement fast cast via calling 'boolTypeCast'. | 434 // TODO(sra): Implement fast cast via calling 'boolTypeCast'. |
| 435 } else if (node.isTypeTest && |
| 436 node.typeArguments.isEmpty && |
| 437 glue.mayGenerateInstanceofCheck(type)) { |
| 438 registerInstanceofCheck(clazz); |
| 439 return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]); |
422 } | 440 } |
423 | 441 |
424 // The helper we use needs the JSArray class to exist, but for some | 442 // The helper we use needs the JSArray class to exist, but for some |
425 // reason the helper does not cause this dependency to be registered. | 443 // reason the helper does not cause this dependency to be registered. |
426 // TODO(asgerf): Most programs need List anyway, but we should fix this. | 444 // TODO(asgerf): Most programs need List anyway, but we should fix this. |
427 registry.registerInstantiatedClass(glue.listClass); | 445 registry.registerInstantiatedClass(glue.listClass); |
428 | 446 |
429 // We use one of the two helpers: | 447 // We use one of the two helpers: |
430 // | 448 // |
431 // checkSubtype(value, $isT, typeArgs, $asT) | 449 // checkSubtype(value, $isT, typeArgs, $asT) |
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 void registerDefaultParameterValues(ExecutableElement element) { | 1158 void registerDefaultParameterValues(ExecutableElement element) { |
1141 if (element is! FunctionElement) return; | 1159 if (element is! FunctionElement) return; |
1142 FunctionElement function = element; | 1160 FunctionElement function = element; |
1143 if (function.isStatic) return; // Defaults are inlined at call sites. | 1161 if (function.isStatic) return; // Defaults are inlined at call sites. |
1144 function.functionSignature.forEachOptionalParameter((param) { | 1162 function.functionSignature.forEachOptionalParameter((param) { |
1145 ConstantValue constant = glue.getDefaultParameterValue(param); | 1163 ConstantValue constant = glue.getDefaultParameterValue(param); |
1146 registry.registerCompileTimeConstant(constant); | 1164 registry.registerCompileTimeConstant(constant); |
1147 }); | 1165 }); |
1148 } | 1166 } |
1149 } | 1167 } |
OLD | NEW |