| 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 dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
| 6 | 6 |
| 7 import '../../constants/values.dart' show ConstantValue; | 7 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue; |
| 8 import '../../dart2jslib.dart' show Compiler; | 8 import '../../dart2jslib.dart' show Compiler; |
| 9 import '../../dart_types.dart' show DartType; | 9 import '../../dart_types.dart' show DartType; |
| 10 import '../../elements/elements.dart' show ClassElement; | 10 import '../../elements/elements.dart' show ClassElement, FunctionElement; |
| 11 import '../../js/js.dart' as js; | 11 import '../../js/js.dart' as js; |
| 12 import '../../js_backend/js_backend.dart' show | 12 import '../../js_backend/js_backend.dart' show |
| 13 JavaScriptBackend, | 13 JavaScriptBackend, |
| 14 Namer, | 14 Namer, |
| 15 ConstantEmitter; | 15 ConstantEmitter; |
| 16 | 16 |
| 17 import '../js_emitter.dart' show | 17 import '../js_emitter.dart' show |
| 18 NativeEmitter; | 18 NativeEmitter; |
| 19 | 19 |
| 20 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show | 20 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show |
| (...skipping 10 matching lines...) Expand all Loading... |
| 31 METADATA, | 31 METADATA, |
| 32 TYPE_TO_INTERCEPTOR_MAP; | 32 TYPE_TO_INTERCEPTOR_MAP; |
| 33 | 33 |
| 34 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; | 34 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; |
| 35 import '../model.dart'; | 35 import '../model.dart'; |
| 36 | 36 |
| 37 | 37 |
| 38 class ModelEmitter { | 38 class ModelEmitter { |
| 39 final Compiler compiler; | 39 final Compiler compiler; |
| 40 final Namer namer; | 40 final Namer namer; |
| 41 final ConstantEmitter constantEmitter; | 41 ConstantEmitter constantEmitter; |
| 42 final NativeEmitter nativeEmitter; | 42 final NativeEmitter nativeEmitter; |
| 43 | 43 |
| 44 JavaScriptBackend get backend => compiler.backend; | 44 JavaScriptBackend get backend => compiler.backend; |
| 45 | 45 |
| 46 /// For deferred loading we communicate the initializers via this global var. | 46 /// For deferred loading we communicate the initializers via this global var. |
| 47 static const String deferredInitializersGlobal = | 47 static const String deferredInitializersGlobal = |
| 48 r"$__dart_deferred_initializers__"; | 48 r"$__dart_deferred_initializers__"; |
| 49 | 49 |
| 50 static const String deferredExtension = "part.js"; | 50 static const String deferredExtension = "part.js"; |
| 51 | 51 |
| 52 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) | 52 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) |
| 53 : this.compiler = compiler, | 53 : this.compiler = compiler, |
| 54 this.namer = namer, | 54 this.namer = namer { |
| 55 constantEmitter = | 55 // TODO(floitsch): remove hard-coded name. |
| 56 new ConstantEmitter(compiler, namer, makeConstantListTemplate); | 56 // TODO(floitsch): there is no harm in caching the template. |
| 57 js.Template makeConstantListTemplate = |
| 58 js.js.uncachedExpressionTemplate('makeConstList(#)'); |
| 59 |
| 60 this.constantEmitter = new ConstantEmitter( |
| 61 compiler, namer, this.generateConstantReference, |
| 62 makeConstantListTemplate); |
| 63 } |
| 57 | 64 |
| 58 js.Expression generateEmbeddedGlobalAccess(String global) { | 65 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 59 // TODO(floitsch): We should not use "init" for globals. | 66 // TODO(floitsch): We should not use "init" for globals. |
| 60 return js.js("init.$global"); | 67 return js.js("init.$global"); |
| 61 } | 68 } |
| 62 | 69 |
| 70 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 71 if (constant.isFunction) return true; // Already emitted. |
| 72 if (constant.isPrimitive) return true; // Inlined. |
| 73 if (constant.isDummy) return true; // Inlined. |
| 74 // The name is null when the constant is already a JS constant. |
| 75 // TODO(floitsch): every constant should be registered, so that we can |
| 76 // share the ones that take up too much space (like some strings). |
| 77 if (namer.constantName(constant) == null) return true; |
| 78 return false; |
| 79 } |
| 80 |
| 81 // TODO(floitsch): copied from OldEmitter. Adjust or share. |
| 82 int compareConstants(ConstantValue a, ConstantValue b) { |
| 83 // Inlined constants don't affect the order and sometimes don't even have |
| 84 // names. |
| 85 int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1; |
| 86 int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1; |
| 87 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; |
| 88 |
| 89 // Emit constant interceptors first. Constant interceptors for primitives |
| 90 // might be used by code that builds other constants. See Issue 18173. |
| 91 if (a.isInterceptor != b.isInterceptor) { |
| 92 return a.isInterceptor ? -1 : 1; |
| 93 } |
| 94 |
| 95 // Sorting by the long name clusters constants with the same constructor |
| 96 // which compresses a tiny bit better. |
| 97 int r = namer.constantLongName(a).compareTo(namer.constantLongName(b)); |
| 98 if (r != 0) return r; |
| 99 // Resolve collisions in the long name by using the constant name (i.e. JS |
| 100 // name) which is unique. |
| 101 return namer.constantName(a).compareTo(namer.constantName(b)); |
| 102 } |
| 103 |
| 104 js.Expression generateStaticClosureAccess(FunctionElement element) { |
| 105 return js.js('#.#()', |
| 106 [namer.globalObjectFor(element), namer.getStaticClosureName(element)]); |
| 107 } |
| 108 |
| 109 js.Expression generateConstantReference(ConstantValue value) { |
| 110 if (value.isFunction) { |
| 111 FunctionConstantValue functionConstant = value; |
| 112 return generateStaticClosureAccess(functionConstant.element); |
| 113 } |
| 114 |
| 115 // We are only interested in the "isInlined" part, but it does not hurt to |
| 116 // test for the other predicates. |
| 117 if (isConstantInlinedOrAlreadyEmitted(value)) { |
| 118 return constantEmitter.generate(value); |
| 119 } |
| 120 return js.js('#.#', [namer.globalObjectForConstant(value), |
| 121 namer.constantName(value)]); |
| 122 } |
| 123 |
| 63 int emitProgram(Program program) { | 124 int emitProgram(Program program) { |
| 64 List<Fragment> fragments = program.fragments; | 125 List<Fragment> fragments = program.fragments; |
| 65 MainFragment mainFragment = fragments.first; | 126 MainFragment mainFragment = fragments.first; |
| 66 | 127 |
| 67 int totalSize = 0; | 128 int totalSize = 0; |
| 68 | 129 |
| 69 // We have to emit the deferred fragments first, since we need their | 130 // We have to emit the deferred fragments first, since we need their |
| 70 // deferred hash (which depends on the output) when emitting the main | 131 // deferred hash (which depends on the output) when emitting the main |
| 71 // fragment. | 132 // fragment. |
| 72 fragments.skip(1).forEach((DeferredFragment deferredUnit) { | 133 fragments.skip(1).forEach((DeferredFragment deferredUnit) { |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 new js.VariableDeclaration(e.name, allowRename: false), | 259 new js.VariableDeclaration(e.name, allowRename: false), |
| 199 new js.ObjectInitializer(const []))).toList())), | 260 new js.ObjectInitializer(const []))).toList())), |
| 200 js.js.statement('var holders = #', new js.ArrayInitializer( | 261 js.js.statement('var holders = #', new js.ArrayInitializer( |
| 201 holders.map((e) => new js.VariableUse(e.name)) | 262 holders.map((e) => new js.VariableUse(e.name)) |
| 202 .toList(growable: false))), | 263 .toList(growable: false))), |
| 203 js.js.statement('var holdersMap = Object.create(null)') | 264 js.js.statement('var holdersMap = Object.create(null)') |
| 204 ]; | 265 ]; |
| 205 return new js.Block(statements); | 266 return new js.Block(statements); |
| 206 } | 267 } |
| 207 | 268 |
| 208 static js.Template get makeConstantListTemplate { | |
| 209 // TODO(floitsch): remove hard-coded name. | |
| 210 // TODO(floitsch): there is no harm in caching the template. | |
| 211 return js.js.uncachedExpressionTemplate('makeConstList(#)'); | |
| 212 } | |
| 213 | |
| 214 js.Block emitEmbeddedGlobals(Program program) { | 269 js.Block emitEmbeddedGlobals(Program program) { |
| 215 List<js.Property> globals = <js.Property>[]; | 270 List<js.Property> globals = <js.Property>[]; |
| 216 | 271 |
| 217 if (program.loadMap.isNotEmpty) { | 272 if (program.loadMap.isNotEmpty) { |
| 218 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap)); | 273 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap)); |
| 219 } | 274 } |
| 220 | 275 |
| 221 if (program.typeToInterceptorMap != null) { | 276 if (program.typeToInterceptorMap != null) { |
| 222 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), | 277 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), |
| 223 program.typeToInterceptorMap)); | 278 program.typeToInterceptorMap)); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 | 434 |
| 380 js.LiteralString immediateString = unparse(compiler, immediateCode); | 435 js.LiteralString immediateString = unparse(compiler, immediateCode); |
| 381 js.ArrayInitializer hunk = | 436 js.ArrayInitializer hunk = |
| 382 new js.ArrayInitializer([deferredArray, immediateString]); | 437 new js.ArrayInitializer([deferredArray, immediateString]); |
| 383 | 438 |
| 384 return js.js("$deferredInitializersGlobal[$hash] = #", hunk); | 439 return js.js("$deferredInitializersGlobal[$hash] = #", hunk); |
| 385 } | 440 } |
| 386 | 441 |
| 387 js.Block emitConstants(List<Constant> constants) { | 442 js.Block emitConstants(List<Constant> constants) { |
| 388 Iterable<js.Statement> statements = constants.map((Constant constant) { | 443 Iterable<js.Statement> statements = constants.map((Constant constant) { |
| 389 js.Expression code = | 444 js.Expression code = constantEmitter.generate(constant.value); |
| 390 constantEmitter.initializationExpression(constant.value); | |
| 391 return js.js.statement("#.# = #;", | 445 return js.js.statement("#.# = #;", |
| 392 [constant.holder.name, constant.name, code]); | 446 [constant.holder.name, constant.name, code]); |
| 393 }); | 447 }); |
| 394 return new js.Block(statements.toList()); | 448 return new js.Block(statements.toList()); |
| 395 } | 449 } |
| 396 | 450 |
| 397 js.Block emitStaticNonFinalFields(List<StaticField> fields) { | 451 js.Block emitStaticNonFinalFields(List<StaticField> fields) { |
| 398 Iterable<js.Statement> statements = fields.map((StaticField field) { | 452 Iterable<js.Statement> statements = fields.map((StaticField field) { |
| 399 return js.js.statement("#.# = #;", | 453 return js.js.statement("#.# = #;", |
| 400 [field.holder.name, field.name, field.code]); | 454 [field.holder.name, field.name, field.code]); |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 f[#argumentCount] = descriptor[pos]; | 679 f[#argumentCount] = descriptor[pos]; |
| 626 f[#defaultArgumentValues] = descriptor[pos + 1]; | 680 f[#defaultArgumentValues] = descriptor[pos + 1]; |
| 627 } | 681 } |
| 628 } else { | 682 } else { |
| 629 proto[name] = descriptor; | 683 proto[name] = descriptor; |
| 630 } | 684 } |
| 631 } | 685 } |
| 632 """; | 686 """; |
| 633 | 687 |
| 634 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { | 688 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { |
| 635 js.Expression result; | |
| 636 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. | 689 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. |
| 637 if (method.optionalParameterDefaultValues is List) { | 690 if (method.optionalParameterDefaultValues is List) { |
| 638 List<ConstantValue> defs = method.optionalParameterDefaultValues; | 691 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues; |
| 639 Iterable<js.Expression> elements = defs.map(constantEmitter.reference); | 692 Iterable<js.Expression> elements = |
| 693 defaultValues.map(generateConstantReference); |
| 640 return new js.ArrayInitializer(elements.toList()); | 694 return new js.ArrayInitializer(elements.toList()); |
| 641 } else { | 695 } else { |
| 642 Map<String, ConstantValue> defs = method.optionalParameterDefaultValues; | 696 Map<String, ConstantValue> defaultValues = |
| 697 method.optionalParameterDefaultValues; |
| 643 List<js.Property> properties = <js.Property>[]; | 698 List<js.Property> properties = <js.Property>[]; |
| 644 defs.forEach((String name, ConstantValue value) { | 699 defaultValues.forEach((String name, ConstantValue value) { |
| 645 properties.add(new js.Property(js.string(name), | 700 properties.add(new js.Property(js.string(name), |
| 646 constantEmitter.reference(value))); | 701 generateConstantReference(value))); |
| 647 }); | 702 }); |
| 648 return new js.ObjectInitializer(properties); | 703 return new js.ObjectInitializer(properties); |
| 649 } | 704 } |
| 650 } | 705 } |
| 651 | 706 |
| 652 Iterable<js.Expression> emitInstanceMethod(Method method) { | 707 Iterable<js.Expression> emitInstanceMethod(Method method) { |
| 653 | 708 |
| 654 List<js.Expression> makeNameCodePair(Method method) { | 709 List<js.Expression> makeNameCodePair(Method method) { |
| 655 return [js.string(method.name), method.code]; | 710 return [js.string(method.name), method.code]; |
| 656 } | 711 } |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1020 | 1075 |
| 1021 var end = Date.now(); | 1076 var end = Date.now(); |
| 1022 // print('Setup: ' + (end - start) + ' ms.'); | 1077 // print('Setup: ' + (end - start) + ' ms.'); |
| 1023 | 1078 |
| 1024 #invokeMain; // Start main. | 1079 #invokeMain; // Start main. |
| 1025 | 1080 |
| 1026 }(Date.now(), #code) | 1081 }(Date.now(), #code) |
| 1027 }"""; | 1082 }"""; |
| 1028 | 1083 |
| 1029 } | 1084 } |
| OLD | NEW |