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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.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 dart2js.js_emitter.lazy_emitter.model_emitter; 5 library dart2js.js_emitter.lazy_emitter.model_emitter;
6 6
7 import '../../compiler.dart' show 7 import '../../compiler.dart' show Compiler;
8 Compiler; 8 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue;
9 import '../../constants/values.dart' show 9 import '../../core_types.dart' show CoreClasses;
10 ConstantValue, 10 import '../../elements/elements.dart' show ClassElement, FunctionElement;
11 FunctionConstantValue;
12 import '../../core_types.dart' show
13 CoreClasses;
14 import '../../elements/elements.dart' show
15 ClassElement,
16 FunctionElement;
17 import '../../js/js.dart' as js; 11 import '../../js/js.dart' as js;
18 import '../../js_backend/js_backend.dart' show 12 import '../../js_backend/js_backend.dart'
19 JavaScriptBackend, 13 show JavaScriptBackend, Namer, ConstantEmitter;
20 Namer,
21 ConstantEmitter;
22 14
23 import '../js_emitter.dart' show NativeEmitter; 15 import '../js_emitter.dart' show NativeEmitter;
24 import '../constant_ordering.dart' show deepCompareConstants; 16 import '../constant_ordering.dart' show deepCompareConstants;
25 17
26 import 'package:js_runtime/shared/embedded_names.dart' show 18 import 'package:js_runtime/shared/embedded_names.dart'
27 CREATE_NEW_ISOLATE, 19 show
28 DEFERRED_LIBRARY_URIS, 20 CREATE_NEW_ISOLATE,
29 DEFERRED_LIBRARY_HASHES, 21 DEFERRED_LIBRARY_URIS,
30 GET_TYPE_FROM_NAME, 22 DEFERRED_LIBRARY_HASHES,
31 INITIALIZE_LOADED_HUNK, 23 GET_TYPE_FROM_NAME,
32 INTERCEPTORS_BY_TAG, 24 INITIALIZE_LOADED_HUNK,
33 IS_HUNK_INITIALIZED, 25 INTERCEPTORS_BY_TAG,
34 IS_HUNK_LOADED, 26 IS_HUNK_INITIALIZED,
35 LEAF_TAGS, 27 IS_HUNK_LOADED,
36 MANGLED_GLOBAL_NAMES, 28 LEAF_TAGS,
37 METADATA, 29 MANGLED_GLOBAL_NAMES,
38 TYPE_TO_INTERCEPTOR_MAP, 30 METADATA,
39 TYPES; 31 TYPE_TO_INTERCEPTOR_MAP,
32 TYPES;
40 33
41 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; 34 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode;
42 import '../model.dart'; 35 import '../model.dart';
43 36
44 class ModelEmitter { 37 class ModelEmitter {
45 final Compiler compiler; 38 final Compiler compiler;
46 final Namer namer; 39 final Namer namer;
47 ConstantEmitter constantEmitter; 40 ConstantEmitter constantEmitter;
48 final NativeEmitter nativeEmitter; 41 final NativeEmitter nativeEmitter;
49 42
50 JavaScriptBackend get backend => compiler.backend; 43 JavaScriptBackend get backend => compiler.backend;
51 44
52 /// For deferred loading we communicate the initializers via this global var. 45 /// For deferred loading we communicate the initializers via this global var.
53 static const String deferredInitializersGlobal = 46 static const String deferredInitializersGlobal =
54 r"$__dart_deferred_initializers__"; 47 r"$__dart_deferred_initializers__";
55 48
56 static const String deferredExtension = "part.js"; 49 static const String deferredExtension = "part.js";
57 50
58 static const String typeNameProperty = r"builtin$cls"; 51 static const String typeNameProperty = r"builtin$cls";
59 52
60 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) 53 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter)
61 : this.compiler = compiler, 54 : this.compiler = compiler,
62 this.namer = namer { 55 this.namer = namer {
63
64 this.constantEmitter = new ConstantEmitter( 56 this.constantEmitter = new ConstantEmitter(
65 compiler, namer, this.generateConstantReference, 57 compiler, namer, this.generateConstantReference, constantListGenerator);
66 constantListGenerator);
67 } 58 }
68 59
69 js.Expression constantListGenerator(js.Expression array) { 60 js.Expression constantListGenerator(js.Expression array) {
70 // TODO(floitsch): remove hard-coded name. 61 // TODO(floitsch): remove hard-coded name.
71 return js.js('makeConstList(#)', [array]); 62 return js.js('makeConstList(#)', [array]);
72 } 63 }
73 64
74 js.Expression generateEmbeddedGlobalAccess(String global) { 65 js.Expression generateEmbeddedGlobalAccess(String global) {
75 return js.js(generateEmbeddedGlobalAccessString(global)); 66 return js.js(generateEmbeddedGlobalAccessString(global));
76 } 67 }
77 68
78 String generateEmbeddedGlobalAccessString(String global) { 69 String generateEmbeddedGlobalAccessString(String global) {
79 // TODO(floitsch): don't use 'init' as global embedder storage. 70 // TODO(floitsch): don't use 'init' as global embedder storage.
80 return 'init.$global'; 71 return 'init.$global';
81 } 72 }
82 73
83 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { 74 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
84 if (constant.isFunction) return true; // Already emitted. 75 if (constant.isFunction) return true; // Already emitted.
85 if (constant.isPrimitive) return true; // Inlined. 76 if (constant.isPrimitive) return true; // Inlined.
86 if (constant.isDummy) return true; // Inlined. 77 if (constant.isDummy) return true; // Inlined.
87 // The name is null when the constant is already a JS constant. 78 // The name is null when the constant is already a JS constant.
88 // TODO(floitsch): every constant should be registered, so that we can 79 // TODO(floitsch): every constant should be registered, so that we can
89 // share the ones that take up too much space (like some strings). 80 // share the ones that take up too much space (like some strings).
90 if (namer.constantName(constant) == null) return true; 81 if (namer.constantName(constant) == null) return true;
91 return false; 82 return false;
92 } 83 }
93 84
94 // TODO(floitsch): copied from full emitter. Adjust or share. 85 // TODO(floitsch): copied from full emitter. Adjust or share.
95 int compareConstants(ConstantValue a, ConstantValue b) { 86 int compareConstants(ConstantValue a, ConstantValue b) {
96 // Inlined constants don't affect the order and sometimes don't even have 87 // Inlined constants don't affect the order and sometimes don't even have
(...skipping 26 matching lines...) Expand all
123 if (value.isFunction) { 114 if (value.isFunction) {
124 FunctionConstantValue functionConstant = value; 115 FunctionConstantValue functionConstant = value;
125 return generateStaticClosureAccess(functionConstant.element); 116 return generateStaticClosureAccess(functionConstant.element);
126 } 117 }
127 118
128 // We are only interested in the "isInlined" part, but it does not hurt to 119 // We are only interested in the "isInlined" part, but it does not hurt to
129 // test for the other predicates. 120 // test for the other predicates.
130 if (isConstantInlinedOrAlreadyEmitted(value)) { 121 if (isConstantInlinedOrAlreadyEmitted(value)) {
131 return constantEmitter.generate(value); 122 return constantEmitter.generate(value);
132 } 123 }
133 return js.js('#.#()', [namer.globalObjectForConstant(value), 124 return js.js('#.#()',
134 namer.constantName(value)]); 125 [namer.globalObjectForConstant(value), namer.constantName(value)]);
135 } 126 }
136 127
137 int emitProgram(Program program) { 128 int emitProgram(Program program) {
138 List<Fragment> fragments = program.fragments; 129 List<Fragment> fragments = program.fragments;
139 MainFragment mainFragment = fragments.first; 130 MainFragment mainFragment = fragments.first;
140 Iterable<Fragment> deferredFragments = program.deferredFragments; 131 Iterable<Fragment> deferredFragments = program.deferredFragments;
141 132
142 int totalSize = 0; 133 int totalSize = 0;
143 134
144 // We have to emit the deferred fragments first, since we need their 135 // We have to emit the deferred fragments first, since we need their
145 // deferred hash (which depends on the output) when emitting the main 136 // deferred hash (which depends on the output) when emitting the main
146 // fragment. 137 // fragment.
147 List<js.Expression> fragmentsCode = deferredFragments.map( 138 List<js.Expression> fragmentsCode =
148 (DeferredFragment deferredUnit) { 139 deferredFragments.map((DeferredFragment deferredUnit) {
149 js.Expression types = 140 js.Expression types =
150 program.metadataTypesForOutputUnit(deferredUnit.outputUnit); 141 program.metadataTypesForOutputUnit(deferredUnit.outputUnit);
151 return emitDeferredFragment(types, deferredUnit, program.holders); 142 return emitDeferredFragment(types, deferredUnit, program.holders);
152 }).toList(); 143 }).toList();
153 144
154 js.Statement mainAst = emitMainFragment(program); 145 js.Statement mainAst = emitMainFragment(program);
155 146
156 js.TokenCounter counter = new js.TokenCounter(); 147 js.TokenCounter counter = new js.TokenCounter();
157 fragmentsCode.forEach(counter.countTokens); 148 fragmentsCode.forEach(counter.countTokens);
158 counter.countTokens(mainAst); 149 counter.countTokens(mainAst);
159 150
160 program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens()); 151 program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
161 152
162 // TODO(johnnniwinther): Support source maps in this emitter. 153 // TODO(johnnniwinther): Support source maps in this emitter.
163 for (int i = 0; i < fragmentsCode.length; ++i) { 154 for (int i = 0; i < fragmentsCode.length; ++i) {
164 String code = js.createCodeBuffer(fragmentsCode[i], compiler).getText(); 155 String code = js.createCodeBuffer(fragmentsCode[i], compiler).getText();
165 totalSize += code.length; 156 totalSize += code.length;
166 compiler.outputProvider(fragments[i+1].outputFileName, deferredExtension) 157 compiler.outputProvider(
158 fragments[i + 1].outputFileName, deferredExtension)
167 ..add(code) 159 ..add(code)
168 ..close(); 160 ..close();
169 } 161 }
170 162
171 String mainCode = js.createCodeBuffer(mainAst, compiler).getText(); 163 String mainCode = js.createCodeBuffer(mainAst, compiler).getText();
172 compiler.outputProvider(mainFragment.outputFileName, 'js') 164 compiler.outputProvider(mainFragment.outputFileName, 'js')
173 ..add(buildGeneratedBy(compiler)) 165 ..add(buildGeneratedBy(compiler))
174 ..add(mainCode) 166 ..add(mainCode)
175 ..close(); 167 ..close();
176 totalSize += mainCode.length; 168 totalSize += mainCode.length;
177 169
178 return totalSize; 170 return totalSize;
179 } 171 }
180 172
181 /// Returns a [js.Literal] that represents the string result of unparsing 173 /// Returns a [js.Literal] that represents the string result of unparsing
182 /// [value]. 174 /// [value].
183 /// 175 ///
184 /// The returned node will, when its string value is requested, pretty-print 176 /// The returned node will, when its string value is requested, pretty-print
185 /// the given [value] and, if [protectForEval] is true, wrap the resulting 177 /// the given [value] and, if [protectForEval] is true, wrap the resulting
186 /// string in parenthesis. The result is also escaped. 178 /// string in parenthesis. The result is also escaped.
187 /// 179 ///
188 /// See [_UnparsedNode] for details. 180 /// See [_UnparsedNode] for details.
189 js.Literal unparse(Compiler compiler, js.Node value, 181 js.Literal unparse(Compiler compiler, js.Node value,
190 {bool protectForEval: true}) { 182 {bool protectForEval: true}) {
191 return new js.UnparsedNode(value, compiler, protectForEval); 183 return new js.UnparsedNode(value, compiler, protectForEval);
192 } 184 }
193 185
194 String buildGeneratedBy(compiler) { 186 String buildGeneratedBy(compiler) {
195 var suffix = ''; 187 var suffix = '';
196 if (compiler.options.hasBuildId) { 188 if (compiler.options.hasBuildId) {
197 suffix = ' version: ${compiler.options.buildId}'; 189 suffix = ' version: ${compiler.options.buildId}';
198 } 190 }
199 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; 191 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
200 } 192 }
201 193
202 js.Statement emitMainFragment(Program program) { 194 js.Statement emitMainFragment(Program program) {
203 MainFragment fragment = program.fragments.first; 195 MainFragment fragment = program.fragments.first;
204 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); 196 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList();
205 elements.add( 197 elements.add(
206 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); 198 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
207 elements.add(emitConstants(fragment.constants)); 199 elements.add(emitConstants(fragment.constants));
208 200
209 js.Expression code = new js.ArrayInitializer(elements); 201 js.Expression code = new js.ArrayInitializer(elements);
210 202
211 Map<String, dynamic> holes = 203 Map<String, dynamic> holes = {
212 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), 204 'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap),
213 'holders': emitHolders(program.holders), 205 'holders': emitHolders(program.holders),
214 'tearOff': buildTearOffCode(backend), 206 'tearOff': buildTearOffCode(backend),
215 'parseFunctionDescriptor': 207 'parseFunctionDescriptor':
216 js.js.statement(parseFunctionDescriptorBoilerplate, 208 js.js.statement(parseFunctionDescriptorBoilerplate, {
217 {'argumentCount': js.string(namer.requiredParameterField), 209 'argumentCount': js.string(namer.requiredParameterField),
218 'defaultArgumentValues': js.string(namer.defaultValuesField), 210 'defaultArgumentValues': js.string(namer.defaultValuesField),
219 'callName': js.string(namer.callNameField)}), 211 'callName': js.string(namer.callNameField)
220 212 }),
221 'cyclicThrow': 213 'cyclicThrow': backend.emitter
222 backend.emitter.staticFunctionAccess( 214 .staticFunctionAccess(backend.helpers.cyclicThrowHelper),
223 backend.helpers.cyclicThrowHelper), 215 'outputContainsConstantList': program.outputContainsConstantList,
224 'outputContainsConstantList': program.outputContainsConstantList, 216 'embeddedGlobals': emitEmbeddedGlobals(program),
225 'embeddedGlobals': emitEmbeddedGlobals(program), 217 'readMetadataTypeFunction': readMetadataTypeFunction,
226 'readMetadataTypeFunction': readMetadataTypeFunction, 218 'staticNonFinals':
227 'staticNonFinals': 219 emitStaticNonFinalFields(fragment.staticNonFinalFields),
228 emitStaticNonFinalFields(fragment.staticNonFinalFields), 220 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
229 'operatorIsPrefix': js.string(namer.operatorIsPrefix), 221 'callName': js.string(namer.callNameField),
230 'callName': js.string(namer.callNameField), 222 'argumentCount': js.string(namer.requiredParameterField),
231 'argumentCount': js.string(namer.requiredParameterField), 223 'defaultArgumentValues': js.string(namer.defaultValuesField),
232 'defaultArgumentValues': js.string(namer.defaultValuesField), 224 'eagerClasses': emitEagerClassInitializations(fragment.libraries),
233 'eagerClasses': emitEagerClassInitializations(fragment.libraries), 225 'invokeMain': fragment.invokeMain,
234 'invokeMain': fragment.invokeMain, 226 'code': code
235 'code': code}; 227 };
236 228
237 holes.addAll(nativeHoles(program)); 229 holes.addAll(nativeHoles(program));
238 230
239 return js.js.statement(boilerplate, holes); 231 return js.js.statement(boilerplate, holes);
240 } 232 }
241 233
242 Map<String, dynamic> nativeHoles(Program program) { 234 Map<String, dynamic> nativeHoles(Program program) {
243 Map<String, dynamic> nativeHoles = <String, dynamic>{}; 235 Map<String, dynamic> nativeHoles = <String, dynamic>{};
244 236
245 js.Statement nativeIsolateAffinityTagInitialization; 237 js.Statement nativeIsolateAffinityTagInitialization;
246 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { 238 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
247 nativeIsolateAffinityTagInitialization = 239 nativeIsolateAffinityTagInitialization =
248 NativeGenerator.generateIsolateAffinityTagInitialization( 240 NativeGenerator.generateIsolateAffinityTagInitialization(
249 backend, 241 backend,
250 generateEmbeddedGlobalAccess, 242 generateEmbeddedGlobalAccess,
251 // TODO(floitsch): internStringFunction. 243 // TODO(floitsch): internStringFunction.
252 js.js("(function(x) { return x; })", [])); 244 js.js("(function(x) { return x; })", []));
253 } else { 245 } else {
254 nativeIsolateAffinityTagInitialization = js.js.statement(";"); 246 nativeIsolateAffinityTagInitialization = js.js.statement(";");
255 } 247 }
256 nativeHoles['nativeIsolateAffinityTagInitialization'] = 248 nativeHoles['nativeIsolateAffinityTagInitialization'] =
257 nativeIsolateAffinityTagInitialization; 249 nativeIsolateAffinityTagInitialization;
258 250
259
260 js.Expression nativeInfoAccess = js.js('nativeInfo', []); 251 js.Expression nativeInfoAccess = js.js('nativeInfo', []);
261 js.Expression constructorAccess = js.js('constructor', []); 252 js.Expression constructorAccess = js.js('constructor', []);
262 Function subclassReadGenerator = (js.Expression subclass) { 253 Function subclassReadGenerator = (js.Expression subclass) {
263 return js.js('holdersMap[#][#].ensureResolved()', [subclass, subclass]); 254 return js.js('holdersMap[#][#].ensureResolved()', [subclass, subclass]);
264 }; 255 };
265 js.Expression interceptorsByTagAccess = 256 js.Expression interceptorsByTagAccess =
266 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG); 257 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG);
267 js.Expression leafTagsAccess = 258 js.Expression leafTagsAccess = generateEmbeddedGlobalAccess(LEAF_TAGS);
268 generateEmbeddedGlobalAccess(LEAF_TAGS);
269 js.Statement nativeInfoHandler = NativeGenerator.buildNativeInfoHandler( 259 js.Statement nativeInfoHandler = NativeGenerator.buildNativeInfoHandler(
270 nativeInfoAccess, 260 nativeInfoAccess,
271 constructorAccess, 261 constructorAccess,
272 subclassReadGenerator, 262 subclassReadGenerator,
273 interceptorsByTagAccess, 263 interceptorsByTagAccess,
274 leafTagsAccess); 264 leafTagsAccess);
275 265
276 nativeHoles['needsNativeSupport'] = program.needsNativeSupport; 266 nativeHoles['needsNativeSupport'] = program.needsNativeSupport;
277 nativeHoles['needsNoNativeSupport'] = !program.needsNativeSupport; 267 nativeHoles['needsNoNativeSupport'] = !program.needsNativeSupport;
278 nativeHoles['nativeInfoHandler'] = nativeInfoHandler; 268 nativeHoles['nativeInfoHandler'] = nativeInfoHandler;
279 269
280 return nativeHoles; 270 return nativeHoles;
281 } 271 }
282 272
283 js.Block emitHolders(List<Holder> holders) { 273 js.Block emitHolders(List<Holder> holders) {
284 // The top-level variables for holders must *not* be renamed by the 274 // The top-level variables for holders must *not* be renamed by the
285 // JavaScript pretty printer because a lot of code already uses the 275 // JavaScript pretty printer because a lot of code already uses the
286 // non-renamed names. The generated code looks like this: 276 // non-renamed names. The generated code looks like this:
287 // 277 //
288 // var H = {}, ..., G = {}; 278 // var H = {}, ..., G = {};
289 // var holders = [ H, ..., G ]; 279 // var holders = [ H, ..., G ];
290 // 280 //
291 // and it is inserted at the top of the top-level function expression 281 // and it is inserted at the top of the top-level function expression
292 // that covers the entire program. 282 // that covers the entire program.
293 283
294 List<js.Statement> statements = [ 284 List<js.Statement> statements = [
295 new js.ExpressionStatement( 285 new js.ExpressionStatement(new js.VariableDeclarationList(holders
296 new js.VariableDeclarationList(holders.map((e) => 286 .map((e) => new js.VariableInitialization(
297 new js.VariableInitialization( 287 new js.VariableDeclaration(e.name, allowRename: false),
298 new js.VariableDeclaration(e.name, allowRename: false), 288 new js.ObjectInitializer(const [])))
299 new js.ObjectInitializer(const []))).toList())), 289 .toList())),
300 js.js.statement('var holders = #', new js.ArrayInitializer( 290 js.js.statement(
301 holders.map((e) => new js.VariableUse(e.name)) 291 'var holders = #',
302 .toList(growable: false))), 292 new js.ArrayInitializer(holders
303 js.js.statement('var holdersMap = Object.create(null)') 293 .map((e) => new js.VariableUse(e.name))
294 .toList(growable: false))),
295 js.js.statement('var holdersMap = Object.create(null)')
304 ]; 296 ];
305 return new js.Block(statements); 297 return new js.Block(statements);
306 } 298 }
307 299
308 js.Block emitEmbeddedGlobals(Program program) { 300 js.Block emitEmbeddedGlobals(Program program) {
309 List<js.Property> globals = <js.Property>[]; 301 List<js.Property> globals = <js.Property>[];
310 302
311 if (program.loadMap.isNotEmpty) { 303 if (program.loadMap.isNotEmpty) {
312 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap)); 304 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap));
313 } 305 }
314 306
315 if (program.typeToInterceptorMap != null) { 307 if (program.typeToInterceptorMap != null) {
316 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), 308 globals.add(new js.Property(
317 program.typeToInterceptorMap)); 309 js.string(TYPE_TO_INTERCEPTOR_MAP), program.typeToInterceptorMap));
318 } 310 }
319 311
320 if (program.hasIsolateSupport) { 312 if (program.hasIsolateSupport) {
321 String isolateName = namer.staticStateHolder; 313 String isolateName = namer.staticStateHolder;
322 globals.add( 314 globals.add(new js.Property(js.string(CREATE_NEW_ISOLATE),
323 new js.Property(js.string(CREATE_NEW_ISOLATE), 315 js.js('function () { return $isolateName; }')));
324 js.js('function () { return $isolateName; }')));
325 // TODO(floitsch): add remaining isolate functions. 316 // TODO(floitsch): add remaining isolate functions.
326 } 317 }
327 318
328 globals.add(emitMangledGlobalNames()); 319 globals.add(emitMangledGlobalNames());
329 320
330 globals.add(emitGetTypeFromName()); 321 globals.add(emitGetTypeFromName());
331 322
332 globals.addAll(emitMetadata(program)); 323 globals.addAll(emitMetadata(program));
333 324
334 if (program.needsNativeSupport) { 325 if (program.needsNativeSupport) {
335 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), 326 globals.add(new js.Property(
336 js.js('Object.create(null)', []))); 327 js.string(INTERCEPTORS_BY_TAG), js.js('Object.create(null)', [])));
337 globals.add(new js.Property(js.string(LEAF_TAGS), 328 globals.add(new js.Property(
338 js.js('Object.create(null)', []))); 329 js.string(LEAF_TAGS), js.js('Object.create(null)', [])));
339 } 330 }
340 331
341 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); 332 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals);
342 333
343 List<js.Statement> statements = 334 List<js.Statement> statements = [
344 [new js.ExpressionStatement( 335 new js.ExpressionStatement(new js.VariableDeclarationList([
345 new js.VariableDeclarationList( 336 new js.VariableInitialization(
346 [new js.VariableInitialization( 337 new js.VariableDeclaration("init", allowRename: false),
347 new js.VariableDeclaration("init", allowRename: false), 338 globalsObject)
348 globalsObject)]))]; 339 ]))
340 ];
349 return new js.Block(statements); 341 return new js.Block(statements);
350 } 342 }
351 343
352 js.Property emitMangledGlobalNames() { 344 js.Property emitMangledGlobalNames() {
353 List<js.Property> names = <js.Property>[]; 345 List<js.Property> names = <js.Property>[];
354 346
355 CoreClasses coreClasses = compiler.coreClasses; 347 CoreClasses coreClasses = compiler.coreClasses;
356 // We want to keep the original names for the most common core classes when 348 // We want to keep the original names for the most common core classes when
357 // calling toString on them. 349 // calling toString on them.
358 List<ClassElement> nativeClassesNeedingUnmangledName = 350 List<ClassElement> nativeClassesNeedingUnmangledName = [
359 [coreClasses.intClass, coreClasses.doubleClass, coreClasses.numClass, 351 coreClasses.intClass,
360 coreClasses.stringClass, coreClasses.boolClass, coreClasses.nullClass, 352 coreClasses.doubleClass,
361 coreClasses.listClass]; 353 coreClasses.numClass,
354 coreClasses.stringClass,
355 coreClasses.boolClass,
356 coreClasses.nullClass,
357 coreClasses.listClass
358 ];
362 nativeClassesNeedingUnmangledName.forEach((element) { 359 nativeClassesNeedingUnmangledName.forEach((element) {
363 names.add(new js.Property(js.quoteName(namer.className(element)), 360 names.add(new js.Property(
364 js.string(element.name))); 361 js.quoteName(namer.className(element)), js.string(element.name)));
365 }); 362 });
366 363
367 return new js.Property(js.string(MANGLED_GLOBAL_NAMES), 364 return new js.Property(
368 new js.ObjectInitializer(names)); 365 js.string(MANGLED_GLOBAL_NAMES), new js.ObjectInitializer(names));
369 } 366 }
370 367
371 js.Statement emitDeferredInitializerGlobal(Map loadMap) { 368 js.Statement emitDeferredInitializerGlobal(Map loadMap) {
372 if (loadMap.isEmpty) return new js.Block.empty(); 369 if (loadMap.isEmpty) return new js.Block.empty();
373 370
374 return js.js.statement(""" 371 return js.js.statement("""
375 if (typeof($deferredInitializersGlobal) === 'undefined') 372 if (typeof($deferredInitializersGlobal) === 'undefined')
376 var $deferredInitializersGlobal = Object.create(null);"""); 373 var $deferredInitializersGlobal = Object.create(null);""");
377 } 374 }
378 375
379 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( 376 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading(
380 Map<String, List<Fragment>> loadMap) { 377 Map<String, List<Fragment>> loadMap) {
381
382 List<js.Property> globals = <js.Property>[]; 378 List<js.Property> globals = <js.Property>[];
383 379
384 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { 380 js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
385 return js.stringArray(fragments.map((DeferredFragment fragment) => 381 return js.stringArray(fragments.map((DeferredFragment fragment) =>
386 "${fragment.outputFileName}.$deferredExtension")); 382 "${fragment.outputFileName}.$deferredExtension"));
387 } 383 }
388 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { 384 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
389 // TODO(floitsch): the hash must depend on the generated code. 385 // TODO(floitsch): the hash must depend on the generated code.
390 return js.numArray( 386 return js.numArray(
391 fragments.map((DeferredFragment fragment) => fragment.hashCode)); 387 fragments.map((DeferredFragment fragment) => fragment.hashCode));
392 } 388 }
393 389
394 List<js.Property> uris = new List<js.Property>(loadMap.length); 390 List<js.Property> uris = new List<js.Property>(loadMap.length);
395 List<js.Property> hashes = new List<js.Property>(loadMap.length); 391 List<js.Property> hashes = new List<js.Property>(loadMap.length);
396 int count = 0; 392 int count = 0;
397 loadMap.forEach((String loadId, List<Fragment> fragmentList) { 393 loadMap.forEach((String loadId, List<Fragment> fragmentList) {
398 uris[count] = 394 uris[count] =
399 new js.Property(js.string(loadId), fragmentUris(fragmentList)); 395 new js.Property(js.string(loadId), fragmentUris(fragmentList));
400 hashes[count] = 396 hashes[count] =
401 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); 397 new js.Property(js.string(loadId), fragmentHashes(fragmentList));
402 count++; 398 count++;
403 }); 399 });
404 400
405 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS), 401 globals.add(new js.Property(
406 new js.ObjectInitializer(uris))); 402 js.string(DEFERRED_LIBRARY_URIS), new js.ObjectInitializer(uris)));
407 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES), 403 globals.add(new js.Property(
408 new js.ObjectInitializer(hashes))); 404 js.string(DEFERRED_LIBRARY_HASHES), new js.ObjectInitializer(hashes)));
409 405
410 js.Expression isHunkLoadedFunction = 406 js.Expression isHunkLoadedFunction =
411 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }"); 407 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }");
412 globals.add(new js.Property(js.string(IS_HUNK_LOADED), 408 globals
413 isHunkLoadedFunction)); 409 .add(new js.Property(js.string(IS_HUNK_LOADED), isHunkLoadedFunction));
414 410
415 js.Expression isHunkInitializedFunction = 411 js.Expression isHunkInitializedFunction =
416 js.js("function(hash) { return false; }"); 412 js.js("function(hash) { return false; }");
417 globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED), 413 globals.add(new js.Property(
418 isHunkInitializedFunction)); 414 js.string(IS_HUNK_INITIALIZED), isHunkInitializedFunction));
419 415
420 js.Expression typesAccess = generateEmbeddedGlobalAccess(TYPES); 416 js.Expression typesAccess = generateEmbeddedGlobalAccess(TYPES);
421 417
422 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the 418 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the
423 /// deferred hunk. 419 /// deferred hunk.
424 js.Expression initializeLoadedHunkFunction = 420 js.Expression initializeLoadedHunkFunction = js.js(
425 js.js(""" 421 """
426 function(hash) { 422 function(hash) {
427 var hunk = $deferredInitializersGlobal[hash]; 423 var hunk = $deferredInitializersGlobal[hash];
428 $setupProgramName(hunk[0], #typesAccess.length); 424 $setupProgramName(hunk[0], #typesAccess.length);
429 eval(hunk[1]); 425 eval(hunk[1]);
430 var deferredTypes = eval(hunk[2]); 426 var deferredTypes = eval(hunk[2]);
431 #typesAccess.push.apply(#typesAccess, deferredTypes); 427 #typesAccess.push.apply(#typesAccess, deferredTypes);
432 }""", {'typesAccess': typesAccess}); 428 }""",
429 {'typesAccess': typesAccess});
433 430
434 globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK), 431 globals.add(new js.Property(
435 initializeLoadedHunkFunction)); 432 js.string(INITIALIZE_LOADED_HUNK), initializeLoadedHunkFunction));
436 433
437 return globals; 434 return globals;
438 } 435 }
439 436
440 js.Property emitGetTypeFromName() { 437 js.Property emitGetTypeFromName() {
441 js.Expression function = 438 js.Expression function = js.js("""function(name) {
442 js.js( """function(name) {
443 return holdersMap[name][name].ensureResolved(); 439 return holdersMap[name][name].ensureResolved();
444 }"""); 440 }""");
445 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); 441 return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
446 } 442 }
447 443
448 static final String readMetadataTypeName = "readMetadataType"; 444 static final String readMetadataTypeName = "readMetadataType";
449 445
450 js.Statement get readMetadataTypeFunction { 446 js.Statement get readMetadataTypeFunction {
451 // Types are non-evaluated and must be compiled at first use. 447 // Types are non-evaluated and must be compiled at first use.
452 // Compiled strings are guaranteed not to be strings, and it's thus safe 448 // Compiled strings are guaranteed not to be strings, and it's thus safe
453 // to use a type-test to determine if a type has already been compiled. 449 // to use a type-test to determine if a type has already been compiled.
454 return js.js.statement('''function $readMetadataTypeName(index) { 450 return js.js.statement(
451 '''function $readMetadataTypeName(index) {
455 var type = #typesAccess[index]; 452 var type = #typesAccess[index];
456 if (typeof type == 'string') { 453 if (typeof type == 'string') {
457 type = expressionCompile(type); 454 type = expressionCompile(type);
458 #typesAccess[index] = type; 455 #typesAccess[index] = type;
459 } 456 }
460 return type; 457 return type;
461 }''', {"typesAccess": generateEmbeddedGlobalAccess(TYPES)}); 458 }''',
459 {"typesAccess": generateEmbeddedGlobalAccess(TYPES)});
462 } 460 }
463 461
464 js.Template get templateForReadType { 462 js.Template get templateForReadType {
465 // TODO(floitsch): make sure that no local variable shadows the access to 463 // TODO(floitsch): make sure that no local variable shadows the access to
466 // the readMetadataType function. 464 // the readMetadataType function.
467 return js.js.expressionTemplateFor('$readMetadataTypeName(#)'); 465 return js.js.expressionTemplateFor('$readMetadataTypeName(#)');
468 } 466 }
469 467
470 static final String readMetadataName = "readLazyMetadata"; 468 static final String readMetadataName = "readLazyMetadata";
471 static final String lazyMetadataName = "lazy_$METADATA"; 469 static final String lazyMetadataName = "lazy_$METADATA";
472 470
473 js.Statement get readMetadataFunction { 471 js.Statement get readMetadataFunction {
474 // Types are non-evaluated and must be compiled at first use. 472 // Types are non-evaluated and must be compiled at first use.
475 // Compiled strings are guaranteed not to be strings, and it's thus safe 473 // Compiled strings are guaranteed not to be strings, and it's thus safe
476 // to use a type-test to determine if a type has already been compiled. 474 // to use a type-test to determine if a type has already been compiled.
477 return js.js.statement('''function $readMetadataName(index) { 475 return js.js.statement(
476 '''function $readMetadataName(index) {
478 var lazyMetadata = #lazyMetadataAccess[index]; 477 var lazyMetadata = #lazyMetadataAccess[index];
479 if (typeof lazyMetadata == 'string') { 478 if (typeof lazyMetadata == 'string') {
480 #metadataAccess[index] = expressionCompile(lazyMetadata); 479 #metadataAccess[index] = expressionCompile(lazyMetadata);
481 #lazyMetadataAccess[index] = null; 480 #lazyMetadataAccess[index] = null;
482 } 481 }
483 return #metadataAccess[index]; 482 return #metadataAccess[index];
484 }''', { 483 }''',
485 "lazyMetadataAccess": generateEmbeddedGlobalAccess(lazyMetadataName), 484 {
486 "metadataAccess": generateEmbeddedGlobalAccess(METADATA) 485 "lazyMetadataAccess": generateEmbeddedGlobalAccess(lazyMetadataName),
487 }); 486 "metadataAccess": generateEmbeddedGlobalAccess(METADATA)
487 });
488 } 488 }
489 489
490 js.Template get templateForReadMetadata { 490 js.Template get templateForReadMetadata {
491 // TODO(floitsch): make sure that no local variable shadows the access to 491 // TODO(floitsch): make sure that no local variable shadows the access to
492 // the readMetadata function. 492 // the readMetadata function.
493 return js.js.expressionTemplateFor('$readMetadataName(#)'); 493 return js.js.expressionTemplateFor('$readMetadataName(#)');
494 } 494 }
495 495
496 List<js.Property> emitMetadata(Program program) { 496 List<js.Property> emitMetadata(Program program) {
497 List<js.Property> metadataGlobals = <js.Property>[]; 497 List<js.Property> metadataGlobals = <js.Property>[];
498 498
499 js.Property createGlobal(js.Expression metadata, String global) { 499 js.Property createGlobal(js.Expression metadata, String global) {
500 return new js.Property(js.string(global), metadata); 500 return new js.Property(js.string(global), metadata);
501 } 501 }
502 502
503 metadataGlobals.add(createGlobal(program.metadata, METADATA)); 503 metadataGlobals.add(createGlobal(program.metadata, METADATA));
504 js.Expression types = 504 js.Expression types =
505 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); 505 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit);
506 metadataGlobals.add(createGlobal(types, TYPES)); 506 metadataGlobals.add(createGlobal(types, TYPES));
507 507
508 return metadataGlobals; 508 return metadataGlobals;
509 } 509 }
510 510
511 js.Expression emitDeferredFragment(js.Expression deferredTypes, 511 js.Expression emitDeferredFragment(js.Expression deferredTypes,
512 DeferredFragment fragment, 512 DeferredFragment fragment, List<Holder> holders) {
513 List<Holder> holders) {
514 // TODO(floitsch): initialize eager classes. 513 // TODO(floitsch): initialize eager classes.
515 // TODO(floitsch): the hash must depend on the output. 514 // TODO(floitsch): the hash must depend on the output.
516 int hash = fragment.hashCode; 515 int hash = fragment.hashCode;
517 516
518 List<js.Expression> deferredCode = 517 List<js.Expression> deferredCode =
519 fragment.libraries.map(emitLibrary).toList(); 518 fragment.libraries.map(emitLibrary).toList();
520 519
521 deferredCode.add( 520 deferredCode.add(
522 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); 521 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
523 deferredCode.add(emitConstants(fragment.constants)); 522 deferredCode.add(emitConstants(fragment.constants));
524 523
525 js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode); 524 js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode);
526 525
527 // This is the code that must be evaluated after all deferred classes have 526 // This is the code that must be evaluated after all deferred classes have
528 // been setup. 527 // been setup.
529 js.Statement immediateCode = new js.Block([ 528 js.Statement immediateCode = new js.Block([
530 emitStaticNonFinalFields(fragment.staticNonFinalFields), 529 emitStaticNonFinalFields(fragment.staticNonFinalFields),
531 emitEagerClassInitializations(fragment.libraries)]); 530 emitEagerClassInitializations(fragment.libraries)
532 531 ]);
533 532
534 js.Literal immediateString = unparse(compiler, immediateCode); 533 js.Literal immediateString = unparse(compiler, immediateCode);
535 534
536 js.ArrayInitializer hunk = 535 js.ArrayInitializer hunk = new js.ArrayInitializer(
537 new js.ArrayInitializer([deferredArray, immediateString, 536 [deferredArray, immediateString, deferredTypes]);
538 deferredTypes]);
539 537
540 return js.js("$deferredInitializersGlobal[$hash] = #", hunk); 538 return js.js("$deferredInitializersGlobal[$hash] = #", hunk);
541 } 539 }
542 540
543 // This string should be referenced wherever JavaScript code makes assumptions 541 // This string should be referenced wherever JavaScript code makes assumptions
544 // on the constants format. 542 // on the constants format.
545 static final String constantsDescription = 543 static final String constantsDescription =
546 "The constants are encoded as a follows:" 544 "The constants are encoded as a follows:"
547 " [constantsHolderIndex, name, code, name2, code2, ...]." 545 " [constantsHolderIndex, name, code, name2, code2, ...]."
548 "The array is completely empty if there is no constant at all."; 546 "The array is completely empty if there is no constant at all.";
549 547
550 js.ArrayInitializer emitConstants(List<Constant> constants) { 548 js.ArrayInitializer emitConstants(List<Constant> constants) {
551 List<js.Expression> data = <js.Expression>[]; 549 List<js.Expression> data = <js.Expression>[];
552 if (constants.isNotEmpty) { 550 if (constants.isNotEmpty) {
553 int holderIndex = constants.first.holder.index; 551 int holderIndex = constants.first.holder.index;
554 data.add(js.number(holderIndex)); 552 data.add(js.number(holderIndex));
555 data.addAll(constants.expand((Constant constant) { 553 data.addAll(constants.expand((Constant constant) {
556 assert(constant.holder.index == holderIndex); 554 assert(constant.holder.index == holderIndex);
557 js.Expression code = constantEmitter.generate(constant.value); 555 js.Expression code = constantEmitter.generate(constant.value);
558 return [js.quoteName(constant.name), unparse(compiler, code)]; 556 return [js.quoteName(constant.name), unparse(compiler, code)];
559 })); 557 }));
560 } 558 }
561 return new js.ArrayInitializer(data); 559 return new js.ArrayInitializer(data);
562 } 560 }
563 561
564 js.Block emitStaticNonFinalFields(List<StaticField> fields) { 562 js.Block emitStaticNonFinalFields(List<StaticField> fields) {
565 Iterable<js.Statement> statements = fields.map((StaticField field) { 563 Iterable<js.Statement> statements = fields.map((StaticField field) {
566 return js.js.statement("#.# = #;", 564 return js.js
567 [field.holder.name, field.name, field.code]); 565 .statement("#.# = #;", [field.holder.name, field.name, field.code]);
568 }); 566 });
569 return new js.Block(statements.toList()); 567 return new js.Block(statements.toList());
570 } 568 }
571 569
572 js.Expression emitLazilyInitializedStatics(List<StaticField> fields) { 570 js.Expression emitLazilyInitializedStatics(List<StaticField> fields) {
573 Iterable fieldDescriptors = fields.expand((field) => 571 Iterable fieldDescriptors = fields.expand((field) => [
574 [ js.quoteName(field.name), 572 js.quoteName(field.name),
575 js.quoteName(namer.deriveLazyInitializerName(field.name)), 573 js.quoteName(namer.deriveLazyInitializerName(field.name)),
576 js.number(field.holder.index), 574 js.number(field.holder.index),
577 emitLazyInitializer(field) ]); 575 emitLazyInitializer(field)
576 ]);
578 return new js.ArrayInitializer(fieldDescriptors.toList(growable: false)); 577 return new js.ArrayInitializer(fieldDescriptors.toList(growable: false));
579 } 578 }
580 579
581 js.Block emitEagerClassInitializations(List<Library> libraries) { 580 js.Block emitEagerClassInitializations(List<Library> libraries) {
582 js.Statement createInstantiation(Class cls) { 581 js.Statement createInstantiation(Class cls) {
583 return js.js.statement('new #.#()', [cls.holder.name, cls.name]); 582 return js.js.statement('new #.#()', [cls.holder.name, cls.name]);
584 } 583 }
585 584
586 List<js.Statement> instantiations = 585 List<js.Statement> instantiations = libraries
587 libraries.expand((Library library) => library.classes) 586 .expand((Library library) => library.classes)
588 .where((Class cls) => cls.isEager) 587 .where((Class cls) => cls.isEager)
589 .map(createInstantiation) 588 .map(createInstantiation)
590 .toList(growable: false); 589 .toList(growable: false);
591 return new js.Block(instantiations); 590 return new js.Block(instantiations);
592 } 591 }
593 592
594 // This string should be referenced wherever JavaScript code makes assumptions 593 // This string should be referenced wherever JavaScript code makes assumptions
595 // on the mixin format. 594 // on the mixin format.
596 static final String nativeInfoDescription = 595 static final String nativeInfoDescription = "A class is encoded as follows:"
597 "A class is encoded as follows:"
598 " [name, class-code, holder-index], or " 596 " [name, class-code, holder-index], or "
599 " [name, class-code, native-info, holder-index]."; 597 " [name, class-code, native-info, holder-index].";
600 598
601 js.Expression emitLibrary(Library library) { 599 js.Expression emitLibrary(Library library) {
602 Iterable staticDescriptors = library.statics.expand(emitStaticMethod); 600 Iterable staticDescriptors = library.statics.expand(emitStaticMethod);
603 601
604 Iterable classDescriptors = library.classes.expand((Class cls) { 602 Iterable classDescriptors = library.classes.expand((Class cls) {
605 js.Literal name = js.quoteName(cls.name); 603 js.Literal name = js.quoteName(cls.name);
606 js.LiteralNumber holderIndex = js.number(cls.holder.index); 604 js.LiteralNumber holderIndex = js.number(cls.holder.index);
607 js.Expression emittedClass = emitClass(cls); 605 js.Expression emittedClass = emitClass(cls);
(...skipping 17 matching lines...) Expand all
625 List<js.Name> fieldNames = const <js.Name>[]; 623 List<js.Name> fieldNames = const <js.Name>[];
626 624
627 // If the class is not directly instantiated we only need it for inheritance 625 // If the class is not directly instantiated we only need it for inheritance
628 // or RTI. In either case we don't need its fields. 626 // or RTI. In either case we don't need its fields.
629 if (cls.isDirectlyInstantiated && !cls.isNative) { 627 if (cls.isDirectlyInstantiated && !cls.isNative) {
630 fieldNames = cls.fields.map((Field field) => field.name).toList(); 628 fieldNames = cls.fields.map((Field field) => field.name).toList();
631 } 629 }
632 js.Name name = cls.name; 630 js.Name name = cls.name;
633 631
634 Iterable<js.Name> assignments = fieldNames.map((js.Name field) { 632 Iterable<js.Name> assignments = fieldNames.map((js.Name field) {
635 return js.js("this.#field = #field", {"field": field}); 633 return js.js("this.#field = #field", {"field": field});
636 }); 634 });
637 635
638 return js.js('function #(#) { # }', [name, fieldNames, assignments]); 636 return js.js('function #(#) { # }', [name, fieldNames, assignments]);
639 } 637 }
640 638
641 Method _generateGetter(Field field) { 639 Method _generateGetter(Field field) {
642 String getterTemplateFor(int flags) { 640 String getterTemplateFor(int flags) {
643 switch (flags) { 641 switch (flags) {
644 case 1: return "function() { return this[#]; }"; 642 case 1:
645 case 2: return "function(receiver) { return receiver[#]; }"; 643 return "function() { return this[#]; }";
646 case 3: return "function(receiver) { return this[#]; }"; 644 case 2:
645 return "function(receiver) { return receiver[#]; }";
646 case 3:
647 return "function(receiver) { return this[#]; }";
647 } 648 }
648 return null; 649 return null;
649 } 650 }
650 651
651 js.Expression fieldName = js.quoteName(field.name); 652 js.Expression fieldName = js.quoteName(field.name);
652 js.Expression code = js.js(getterTemplateFor(field.getterFlags), fieldName); 653 js.Expression code = js.js(getterTemplateFor(field.getterFlags), fieldName);
653 js.Name getterName = namer.deriveGetterName(field.accessorName); 654 js.Name getterName = namer.deriveGetterName(field.accessorName);
654 return new StubMethod(getterName, code); 655 return new StubMethod(getterName, code);
655 } 656 }
656 657
657 Method _generateSetter(Field field) { 658 Method _generateSetter(Field field) {
658 String setterTemplateFor(int flags) { 659 String setterTemplateFor(int flags) {
659 switch (flags) { 660 switch (flags) {
660 case 1: return "function(val) { return this[#] = val; }"; 661 case 1:
661 case 2: return "function(receiver, val) { return receiver[#] = val; }"; 662 return "function(val) { return this[#] = val; }";
662 case 3: return "function(receiver, val) { return this[#] = val; }"; 663 case 2:
664 return "function(receiver, val) { return receiver[#] = val; }";
665 case 3:
666 return "function(receiver, val) { return this[#] = val; }";
663 } 667 }
664 return null; 668 return null;
665 } 669 }
666 js.Expression fieldName = js.quoteName(field.name); 670 js.Expression fieldName = js.quoteName(field.name);
667 js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName); 671 js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName);
668 js.Name setterName = namer.deriveSetterName(field.accessorName); 672 js.Name setterName = namer.deriveSetterName(field.accessorName);
669 return new StubMethod(setterName, code); 673 return new StubMethod(setterName, code);
670 } 674 }
671 675
672 Iterable<Method> _generateGettersSetters(Class cls) { 676 Iterable<Method> _generateGettersSetters(Class cls) {
673 Iterable<Method> getters = cls.fields 677 Iterable<Method> getters = cls.fields
674 .where((Field field) => field.needsGetter) 678 .where((Field field) => field.needsGetter)
675 .map(_generateGetter); 679 .map(_generateGetter);
676 680
677 Iterable<Method> setters = cls.fields 681 Iterable<Method> setters = cls.fields
678 .where((Field field) => field.needsUncheckedSetter) 682 .where((Field field) => field.needsUncheckedSetter)
679 .map(_generateSetter); 683 .map(_generateSetter);
680 684
681 return [getters, setters].expand((x) => x); 685 return [getters, setters].expand((x) => x);
682 } 686 }
683 687
684 // This string should be referenced wherever JavaScript code makes assumptions 688 // This string should be referenced wherever JavaScript code makes assumptions
685 // on the mixin format. 689 // on the mixin format.
686 static final String mixinFormatDescription = 690 static final String mixinFormatDescription =
687 "Mixins have a reference to their mixin class at the place of the usual" 691 "Mixins have a reference to their mixin class at the place of the usual"
688 "constructor. If they are instantiated the constructor follows the" 692 "constructor. If they are instantiated the constructor follows the"
689 "reference."; 693 "reference.";
690 694
691 js.Expression emitClass(Class cls) { 695 js.Expression emitClass(Class cls) {
692 List elements = [js.quoteName(cls.superclassName, allowNull: true), 696 List elements = [
693 js.number(cls.superclassHolderIndex)]; 697 js.quoteName(cls.superclassName, allowNull: true),
698 js.number(cls.superclassHolderIndex)
699 ];
694 700
695 if (cls.isMixinApplication) { 701 if (cls.isMixinApplication) {
696 MixinApplication mixin = cls; 702 MixinApplication mixin = cls;
697 elements.add(js.quoteName(mixin.mixinClass.name)); 703 elements.add(js.quoteName(mixin.mixinClass.name));
698 elements.add(js.number(mixin.mixinClass.holder.index)); 704 elements.add(js.number(mixin.mixinClass.holder.index));
699 if (cls.isDirectlyInstantiated) { 705 if (cls.isDirectlyInstantiated) {
700 elements.add(_generateConstructor(cls)); 706 elements.add(_generateConstructor(cls));
701 } 707 }
702 } else { 708 } else {
703 elements.add(_generateConstructor(cls)); 709 elements.add(_generateConstructor(cls));
704 } 710 }
705 Iterable<Method> methods = cls.methods; 711 Iterable<Method> methods = cls.methods;
706 Iterable<Method> isChecks = cls.isChecks; 712 Iterable<Method> isChecks = cls.isChecks;
707 Iterable<Method> callStubs = cls.callStubs; 713 Iterable<Method> callStubs = cls.callStubs;
708 Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs; 714 Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs;
709 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; 715 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs;
710 Iterable<Method> gettersSetters = _generateGettersSetters(cls); 716 Iterable<Method> gettersSetters = _generateGettersSetters(cls);
711 Iterable<Method> allMethods = 717 Iterable<Method> allMethods = [
712 [methods, isChecks, callStubs, typeVariableReaderStubs, 718 methods,
713 noSuchMethodStubs, gettersSetters].expand((x) => x); 719 isChecks,
720 callStubs,
721 typeVariableReaderStubs,
722 noSuchMethodStubs,
723 gettersSetters
724 ].expand((x) => x);
714 elements.addAll(allMethods.expand(emitInstanceMethod)); 725 elements.addAll(allMethods.expand(emitInstanceMethod));
715 726
716 return unparse(compiler, new js.ArrayInitializer(elements)); 727 return unparse(compiler, new js.ArrayInitializer(elements));
717 } 728 }
718 729
719 js.Expression emitLazyInitializer(StaticField field) { 730 js.Expression emitLazyInitializer(StaticField field) {
720 assert(field.isLazy); 731 assert(field.isLazy);
721 return unparse(compiler, field.code); 732 return unparse(compiler, field.code);
722 } 733 }
723 734
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 if (method.optionalParameterDefaultValues is List) { 817 if (method.optionalParameterDefaultValues is List) {
807 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues; 818 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues;
808 Iterable<js.Expression> elements = 819 Iterable<js.Expression> elements =
809 defaultValues.map(generateConstantReference); 820 defaultValues.map(generateConstantReference);
810 return new js.ArrayInitializer(elements.toList()); 821 return new js.ArrayInitializer(elements.toList());
811 } else { 822 } else {
812 Map<String, ConstantValue> defaultValues = 823 Map<String, ConstantValue> defaultValues =
813 method.optionalParameterDefaultValues; 824 method.optionalParameterDefaultValues;
814 List<js.Property> properties = <js.Property>[]; 825 List<js.Property> properties = <js.Property>[];
815 defaultValues.forEach((String name, ConstantValue value) { 826 defaultValues.forEach((String name, ConstantValue value) {
816 properties.add(new js.Property(js.string(name), 827 properties.add(
817 generateConstantReference(value))); 828 new js.Property(js.string(name), generateConstantReference(value)));
818 }); 829 });
819 return new js.ObjectInitializer(properties); 830 return new js.ObjectInitializer(properties);
820 } 831 }
821 } 832 }
822 833
823 Iterable<js.Expression> emitInstanceMethod(Method method) { 834 Iterable<js.Expression> emitInstanceMethod(Method method) {
824
825 List<js.Expression> makeNameCodePair(Method method) { 835 List<js.Expression> makeNameCodePair(Method method) {
826 return [js.quoteName(method.name), method.code]; 836 return [js.quoteName(method.name), method.code];
827 } 837 }
828 838
829 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { 839 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) {
830 js.Expression callName = stub.callName == null 840 js.Expression callName = stub.callName == null
831 ? new js.LiteralNull() 841 ? new js.LiteralNull()
832 : js.quoteName(stub.callName); 842 : js.quoteName(stub.callName);
833 return [js.quoteName(stub.name), callName, stub.code]; 843 return [js.quoteName(stub.name), callName, stub.code];
834 } 844 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 // stub1_name, stub1_callName, stub1_code, ...] 908 // stub1_name, stub1_callName, stub1_code, ...]
899 var data = [unparse(compiler, method.code)]; 909 var data = [unparse(compiler, method.code)];
900 data.add(js.quoteName(method.callName)); 910 data.add(js.quoteName(method.callName));
901 data.add(js.quoteName(method.tearOffName)); 911 data.add(js.quoteName(method.tearOffName));
902 data.add(method.functionType); 912 data.add(method.functionType);
903 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); 913 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
904 if (method.canBeApplied) { 914 if (method.canBeApplied) {
905 data.add(js.number(method.requiredParameterCount)); 915 data.add(js.number(method.requiredParameterCount));
906 data.add(_encodeOptionalParameterDefaultValues(method)); 916 data.add(_encodeOptionalParameterDefaultValues(method));
907 } 917 }
908 return [js.quoteName(method.name), holderIndex, 918 return [
909 new js.ArrayInitializer(data)]; 919 js.quoteName(method.name),
920 holderIndex,
921 new js.ArrayInitializer(data)
922 ];
910 } else { 923 } else {
911 method.parameterStubs.forEach(_addMethod); 924 method.parameterStubs.forEach(_addMethod);
912 } 925 }
913 } 926 }
914 return output; 927 return output;
915 } 928 }
916 929
917 static final String setupProgramName = "setupProgram"; 930 static final String setupProgramName = "setupProgram";
918 931
919 static final String boilerplate = """ 932 static final String boilerplate = """
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
1250 // Initialize eager classes. 1263 // Initialize eager classes.
1251 #eagerClasses; 1264 #eagerClasses;
1252 1265
1253 var end = Date.now(); 1266 var end = Date.now();
1254 // print('Setup: ' + (end - start) + ' ms.'); 1267 // print('Setup: ' + (end - start) + ' ms.');
1255 1268
1256 #invokeMain; // Start main. 1269 #invokeMain; // Start main.
1257 1270
1258 })(Date.now(), #code) 1271 })(Date.now(), #code)
1259 }"""; 1272 }""";
1260
1261 } 1273 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698