OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 library dart2js.js_emitter.startup_emitter.model_emitter; |
| 6 |
| 7 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue; |
| 8 import '../../dart2jslib.dart' show Compiler; |
| 9 import '../../elements/elements.dart' show ClassElement, FunctionElement; |
| 10 import '../../js/js.dart' as js; |
| 11 import '../../js_backend/js_backend.dart' show |
| 12 JavaScriptBackend, |
| 13 Namer, |
| 14 ConstantEmitter; |
| 15 |
| 16 import '../js_emitter.dart' show AstContainer, NativeEmitter; |
| 17 |
| 18 import 'package:js_runtime/shared/embedded_names.dart' show |
| 19 CREATE_NEW_ISOLATE, |
| 20 DEFERRED_INITIALIZED, |
| 21 DEFERRED_LIBRARY_URIS, |
| 22 DEFERRED_LIBRARY_HASHES, |
| 23 GET_TYPE_FROM_NAME, |
| 24 INITIALIZE_LOADED_HUNK, |
| 25 INTERCEPTORS_BY_TAG, |
| 26 IS_HUNK_INITIALIZED, |
| 27 IS_HUNK_LOADED, |
| 28 LEAF_TAGS, |
| 29 MANGLED_GLOBAL_NAMES, |
| 30 METADATA, |
| 31 NATIVE_SUPERCLASS_TAG_NAME, |
| 32 TYPE_TO_INTERCEPTOR_MAP, |
| 33 TYPES; |
| 34 |
| 35 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; |
| 36 import '../model.dart'; |
| 37 |
| 38 class ModelEmitter { |
| 39 final Compiler compiler; |
| 40 final Namer namer; |
| 41 ConstantEmitter constantEmitter; |
| 42 final NativeEmitter nativeEmitter; |
| 43 |
| 44 JavaScriptBackend get backend => compiler.backend; |
| 45 |
| 46 /// For deferred loading we communicate the initializers via this global var. |
| 47 static const String deferredInitializersGlobal = |
| 48 r"$__dart_deferred_initializers__"; |
| 49 |
| 50 static const String deferredExtension = "part.js"; |
| 51 |
| 52 static const String typeNameProperty = r"builtin$cls"; |
| 53 |
| 54 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) |
| 55 : this.compiler = compiler, |
| 56 this.namer = namer { |
| 57 this.constantEmitter = new ConstantEmitter( |
| 58 compiler, namer, this.generateConstantReference, |
| 59 constantListGenerator); |
| 60 } |
| 61 |
| 62 js.Expression constantListGenerator(js.Expression array) { |
| 63 // TODO(floitsch): remove hard-coded name. |
| 64 return js.js('makeConstList(#)', [array]); |
| 65 } |
| 66 |
| 67 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 68 return js.js(generateEmbeddedGlobalAccessString(global)); |
| 69 } |
| 70 |
| 71 String generateEmbeddedGlobalAccessString(String global) { |
| 72 // TODO(floitsch): don't use 'init' as global embedder storage. |
| 73 return 'init.$global'; |
| 74 } |
| 75 |
| 76 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 77 if (constant.isFunction) return true; // Already emitted. |
| 78 if (constant.isPrimitive) return true; // Inlined. |
| 79 if (constant.isDummy) return true; // Inlined. |
| 80 return false; |
| 81 } |
| 82 |
| 83 // TODO(floitsch): copied from OldEmitter. Adjust or share. |
| 84 int compareConstants(ConstantValue a, ConstantValue b) { |
| 85 // Inlined constants don't affect the order and sometimes don't even have |
| 86 // names. |
| 87 int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1; |
| 88 int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1; |
| 89 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; |
| 90 |
| 91 // Emit constant interceptors first. Constant interceptors for primitives |
| 92 // might be used by code that builds other constants. See Issue 18173. |
| 93 if (a.isInterceptor != b.isInterceptor) { |
| 94 return a.isInterceptor ? -1 : 1; |
| 95 } |
| 96 |
| 97 // Sorting by the long name clusters constants with the same constructor |
| 98 // which compresses a tiny bit better. |
| 99 int r = namer.constantLongName(a).compareTo(namer.constantLongName(b)); |
| 100 if (r != 0) return r; |
| 101 // Resolve collisions in the long name by using the constant name (i.e. JS |
| 102 // name) which is unique. |
| 103 return namer.constantName(a).compareTo(namer.constantName(b)); |
| 104 } |
| 105 |
| 106 js.Expression generateStaticClosureAccess(FunctionElement element) { |
| 107 return js.js('#.#()', |
| 108 [namer.globalObjectFor(element), namer.staticClosureName(element)]); |
| 109 } |
| 110 |
| 111 js.Expression generateConstantReference(ConstantValue value) { |
| 112 if (value.isFunction) { |
| 113 FunctionConstantValue functionConstant = value; |
| 114 return generateStaticClosureAccess(functionConstant.element); |
| 115 } |
| 116 |
| 117 // We are only interested in the "isInlined" part, but it does not hurt to |
| 118 // test for the other predicates. |
| 119 if (isConstantInlinedOrAlreadyEmitted(value)) { |
| 120 return constantEmitter.generate(value); |
| 121 } |
| 122 return js.js('#.#', [namer.globalObjectForConstant(value), |
| 123 namer.constantName(value)]); |
| 124 } |
| 125 |
| 126 int emitProgram(Program program) { |
| 127 // TODO(floitsch): implement. |
| 128 throw new UnimplementedError("startup-emitter.emitProgram"); |
| 129 } |
| 130 } |
OLD | NEW |