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

Side by Side Diff: frog/leg/compiler.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « frog/leg/compile_time_constants.dart ('k') | frog/leg/dart2js.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 class WorkItem {
6 final Element element;
7 TreeElements resolutionTree;
8 Function run;
9 bool allowSpeculativeOptimization = true;
10 List<HTypeGuard> guards = const <HTypeGuard>[];
11
12 WorkItem.toCompile(this.element) : resolutionTree = null {
13 run = this.compile;
14 }
15
16 WorkItem.toCodegen(this.element, this.resolutionTree) {
17 run = this.codegen;
18 }
19
20 bool isAnalyzed() => resolutionTree != null;
21
22 int hashCode() => element.hashCode();
23
24 String compile(Compiler compiler) {
25 return compiler.compile(this);
26 }
27
28 String codegen(Compiler compiler) {
29 return compiler.codegen(this);
30 }
31 }
32
33 class Compiler implements DiagnosticListener {
34 Queue<WorkItem> worklist;
35 Universe universe;
36 String assembledCode;
37 Namer namer;
38 Types types;
39 final String currentDirectory;
40
41 final Tracer tracer;
42
43 CompilerTask measuredTask;
44 Element _currentElement;
45 LibraryElement coreLibrary;
46 LibraryElement coreImplLibrary;
47 LibraryElement isolateLibrary;
48 LibraryElement jsHelperLibrary;
49 LibraryElement mainApp;
50 ClassElement objectClass;
51 ClassElement closureClass;
52 ClassElement dynamicClass;
53 ClassElement boolClass;
54 ClassElement numClass;
55 ClassElement intClass;
56 ClassElement doubleClass;
57 ClassElement stringClass;
58 ClassElement functionClass;
59 ClassElement nullClass;
60 ClassElement listClass;
61
62 Element get currentElement() => _currentElement;
63 withCurrentElement(Element element, f()) {
64 Element old = currentElement;
65 _currentElement = element;
66 try {
67 return f();
68 } finally {
69 _currentElement = old;
70 }
71 }
72
73 List<CompilerTask> tasks;
74 ScannerTask scanner;
75 DietParserTask dietParser;
76 ParserTask parser;
77 TreeValidatorTask validator;
78 ResolverTask resolver;
79 TypeCheckerTask checker;
80 SsaBuilderTask builder;
81 SsaOptimizerTask optimizer;
82 SsaCodeGeneratorTask generator;
83 CodeEmitterTask emitter;
84 ConstantHandler constantHandler;
85 EnqueueTask enqueuer;
86
87 static final SourceString MAIN = const SourceString('main');
88 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod');
89 static final SourceString NO_SUCH_METHOD_EXCEPTION =
90 const SourceString('NoSuchMethodException');
91 static final SourceString START_ROOT_ISOLATE =
92 const SourceString('startRootIsolate');
93 bool enabledNoSuchMethod = false;
94
95 bool workListIsClosed = false;
96
97 Stopwatch codegenProgress;
98
99 Compiler.withCurrentDirectory(String this.currentDirectory,
100 [this.tracer = const Tracer()])
101 : types = new Types(),
102 universe = new Universe(),
103 worklist = new Queue<WorkItem>(),
104 codegenProgress = new Stopwatch.start() {
105 namer = new Namer(this);
106 constantHandler = new ConstantHandler(this);
107 scanner = new ScannerTask(this);
108 dietParser = new DietParserTask(this);
109 parser = new ParserTask(this);
110 validator = new TreeValidatorTask(this);
111 resolver = new ResolverTask(this);
112 checker = new TypeCheckerTask(this);
113 builder = new SsaBuilderTask(this);
114 optimizer = new SsaOptimizerTask(this);
115 generator = new SsaCodeGeneratorTask(this);
116 emitter = new CodeEmitterTask(this);
117 enqueuer = new EnqueueTask(this);
118 tasks = [scanner, dietParser, parser, resolver, checker,
119 builder, optimizer, generator,
120 emitter, constantHandler, enqueuer];
121 }
122
123 void ensure(bool condition) {
124 if (!condition) cancel('failed assertion in leg');
125 }
126
127 void unimplemented(String methodName,
128 [Node node, Token token, HInstruction instruction,
129 Element element]) {
130 internalError("$methodName not implemented",
131 node, token, instruction, element);
132 }
133
134 void internalError(String message,
135 [Node node, Token token, HInstruction instruction,
136 Element element]) {
137 cancel("${red('internal error:')} $message",
138 node, token, instruction, element);
139 }
140
141 void internalErrorOnElement(Element element, String message) {
142 withCurrentElement(element, () {
143 internalError(message, element: element);
144 });
145 }
146
147 void cancel([String reason, Node node, Token token,
148 HInstruction instruction, Element element]) {
149 SourceSpan span = const SourceSpan(null, null, null);
150 if (node !== null) {
151 span = spanFromNode(node);
152 } else if (token !== null) {
153 span = spanFromTokens(token, token);
154 } else if (instruction !== null) {
155 span = spanFromElement(currentElement);
156 } else if (element !== null) {
157 span = spanFromElement(element);
158 }
159 reportDiagnostic(span, red(reason), true);
160 throw new CompilerCancelledException(reason);
161 }
162
163 void log(message) {
164 reportDiagnostic(null, message, false);
165 }
166
167 void enqueue(WorkItem work) {
168 if (workListIsClosed) {
169 internalErrorOnElement(work.element, "work list is closed");
170 }
171 worklist.add(work);
172 }
173
174 bool run(Uri uri) {
175 try {
176 runCompiler(uri);
177 } catch (CompilerCancelledException exception) {
178 log(exception.toString());
179 log('compilation failed');
180 return false;
181 }
182 tracer.close();
183 log('compilation succeeded');
184 return true;
185 }
186
187 void enableNoSuchMethod(Element element) {
188 if (enabledNoSuchMethod) return;
189 if (element.enclosingElement == objectClass) return;
190 enabledNoSuchMethod = true;
191 enqueuer.registerInvocation(NO_SUCH_METHOD, new Invocation(2));
192 }
193
194 void enableIsolateSupport(LibraryElement element) {
195 isolateLibrary = element;
196 addToWorkList(element.find(START_ROOT_ISOLATE));
197 }
198
199 bool hasIsolateSupport() => isolateLibrary !== null;
200
201 void onLibraryLoaded(LibraryElement library, Uri uri) {
202 if (uri.toString() == 'dart:isolate') {
203 enableIsolateSupport(library);
204 }
205 if (dynamicClass !== null) {
206 // When loading the built-in libraries, dynamicClass is null. We
207 // take advantage of this as core and coreimpl import js_helper
208 // and see Dynamic this way.
209 withCurrentElement(dynamicClass, () {
210 library.define(dynamicClass, this);
211 });
212 }
213 }
214
215 abstract LibraryElement scanBuiltinLibrary(String filename);
216
217 void initializeSpecialClasses() {
218 objectClass = coreLibrary.find(const SourceString('Object'));
219 boolClass = coreLibrary.find(const SourceString('bool'));
220 numClass = coreLibrary.find(const SourceString('num'));
221 intClass = coreLibrary.find(const SourceString('int'));
222 doubleClass = coreLibrary.find(const SourceString('double'));
223 stringClass = coreLibrary.find(const SourceString('String'));
224 functionClass = coreLibrary.find(const SourceString('Function'));
225 listClass = coreLibrary.find(const SourceString('List'));
226 closureClass = jsHelperLibrary.find(const SourceString('Closure'));
227 dynamicClass = jsHelperLibrary.find(const SourceString('Dynamic'));
228 nullClass = jsHelperLibrary.find(const SourceString('Null'));
229 }
230
231 void scanBuiltinLibraries() {
232 coreImplLibrary = scanBuiltinLibrary('coreimpl.dart');
233 jsHelperLibrary = scanBuiltinLibrary('js_helper.dart');
234 coreLibrary = scanBuiltinLibrary('core.dart');
235
236 // Since coreLibrary import the libraries "coreimpl", and
237 // "js_helper", coreLibrary is null when they are being built. So
238 // we add the implicit import of coreLibrary now. This can be
239 // cleaned up when we have proper support for "dart:core" and
240 // don't need to access it through the field "coreLibrary".
241 // TODO(ahe): Clean this up as described above.
242 scanner.importLibrary(coreImplLibrary, coreLibrary, null);
243 scanner.importLibrary(jsHelperLibrary, coreLibrary, null);
244 addForeignFunctions(jsHelperLibrary);
245
246 universe.libraries['dart:core'] = coreLibrary;
247 universe.libraries['dart:coreimpl'] = coreImplLibrary;
248
249 initializeSpecialClasses();
250 }
251
252 /** Define the JS helper functions in the given library. */
253 void addForeignFunctions(LibraryElement library) {
254 library.define(new ForeignElement(
255 const SourceString('JS'), library), this);
256 library.define(new ForeignElement(
257 const SourceString('UNINTERCEPTED'), library), this);
258 library.define(new ForeignElement(
259 const SourceString('JS_HAS_EQUALS'), library), this);
260 library.define(new ForeignElement(
261 const SourceString('JS_CURRENT_ISOLATE'), library), this);
262 library.define(new ForeignElement(
263 const SourceString('JS_CALL_IN_ISOLATE'), library), this);
264 library.define(new ForeignElement(
265 const SourceString('DART_CLOSURE_TO_JS'), library), this);
266 }
267
268 void runCompiler(Uri uri) {
269 scanBuiltinLibraries();
270 mainApp = scanner.loadLibrary(uri, null);
271 final Element mainMethod = mainApp.find(MAIN);
272 if (mainMethod === null) {
273 withCurrentElement(mainApp, () => cancel('Could not find $MAIN'));
274 } else {
275 withCurrentElement(mainMethod, () {
276 if (!mainMethod.isFunction()) {
277 cancel('main is not a function', element: mainMethod);
278 }
279 FunctionParameters parameters = mainMethod.computeParameters(this);
280 if (parameters.parameterCount > 0) {
281 cancel('main cannot have parameters', element: mainMethod);
282 }
283 });
284 }
285 native.processNativeClasses(this, universe.libraries.getValues());
286 enqueue(new WorkItem.toCompile(mainMethod));
287 codegenProgress.reset();
288 while (!worklist.isEmpty()) {
289 WorkItem work = worklist.removeLast();
290 withCurrentElement(work.element, () => (work.run)(this));
291 }
292 workListIsClosed = true;
293 assert(enqueuer.checkNoEnqueuedInvokedInstanceMethods());
294 enqueuer.registerFieldClosureInvocations();
295 emitter.assembleProgram();
296 if (!worklist.isEmpty()) {
297 internalErrorOnElement(worklist.first().element,
298 "work list is not empty");
299 }
300 }
301
302 TreeElements analyzeElement(Element element) {
303 assert(parser !== null);
304 Node tree = parser.parse(element);
305 validator.validate(tree);
306 TreeElements elements = resolver.resolve(element);
307 checker.check(tree, elements);
308 return elements;
309 }
310
311 TreeElements analyze(WorkItem work) {
312 work.resolutionTree = analyzeElement(work.element);
313 return work.resolutionTree;
314 }
315
316 String codegen(WorkItem work) {
317 if (codegenProgress.elapsedInMs() > 500) {
318 // TODO(ahe): Add structured diagnostics to the compiler API and
319 // use it to separate this from the --verbose option.
320 log('compiled ${universe.generatedCode.length} methods');
321 codegenProgress.reset();
322 }
323 if (work.element.kind.category == ElementCategory.VARIABLE) {
324 constantHandler.compileWorkItem(work);
325 return null;
326 } else {
327 HGraph graph = builder.build(work);
328 optimizer.optimize(work, graph);
329 if (work.allowSpeculativeOptimization
330 && optimizer.trySpeculativeOptimizations(work, graph)) {
331 String code = generator.generateBailoutMethod(work, graph);
332 universe.addBailoutCode(work, code);
333 optimizer.prepareForSpeculativeOptimizations(work, graph);
334 optimizer.optimize(work, graph);
335 code = generator.generateMethod(work, graph);
336 universe.addGeneratedCode(work, code);
337 return code;
338 } else {
339 String code = generator.generateMethod(work, graph);
340 universe.addGeneratedCode(work, code);
341 return code;
342 }
343 }
344 }
345
346 String compile(WorkItem work) {
347 String code = universe.generatedCode[work.element];
348 if (code !== null) return code;
349 analyze(work);
350 return codegen(work);
351 }
352
353 void addToWorkList(Element element) {
354 if (workListIsClosed) {
355 internalErrorOnElement(element, "work list is closed");
356 }
357 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) {
358 registerInstantiatedClass(element.enclosingElement);
359 }
360 worklist.add(new WorkItem.toCompile(element));
361 }
362
363 void registerStaticUse(Element element) {
364 addToWorkList(element);
365 }
366
367 void registerGetOfStaticFunction(FunctionElement element) {
368 registerStaticUse(element);
369 universe.staticFunctionsNeedingGetter.add(element);
370 }
371
372 void registerDynamicInvocation(SourceString methodName, Selector selector) {
373 assert(selector !== null);
374 enqueuer.registerInvocation(methodName, selector);
375 }
376
377 void registerDynamicGetter(SourceString methodName) {
378 enqueuer.registerGetter(methodName);
379 }
380
381 void registerDynamicSetter(SourceString methodName) {
382 enqueuer.registerSetter(methodName);
383 }
384
385 void registerInstantiatedClass(ClassElement element) {
386 universe.instantiatedClasses.add(element);
387 enqueuer.onRegisterInstantiatedClass(element);
388 }
389
390 // TODO(ngeoffray): This should get a type.
391 void registerIsCheck(Element element) {
392 universe.isChecks.add(element);
393 }
394
395 Type resolveType(ClassElement element) {
396 return withCurrentElement(element, () => resolver.resolveType(element));
397 }
398
399 FunctionParameters resolveSignature(FunctionElement element) {
400 return withCurrentElement(element,
401 () => resolver.resolveSignature(element));
402 }
403
404 Constant compileVariable(VariableElement element) {
405 return withCurrentElement(element, () {
406 return constantHandler.compileVariable(element);
407 });
408 }
409
410 reportWarning(Node node, var message) {
411 if (message is ResolutionWarning) {
412 // TODO(ahe): Don't supress this warning when we support type variables.
413 if (message.message.kind === MessageKind.CANNOT_RESOLVE_TYPE) return;
414 } else if (message is TypeWarning) {
415 // TODO(ahe): Don't supress these warning when the type checker
416 // is more complete.
417 if (message.message.kind === MessageKind.NOT_ASSIGNABLE) return;
418 if (message.message.kind === MessageKind.MISSING_RETURN) return;
419 if (message.message.kind === MessageKind.ADDITIONAL_ARGUMENT) return;
420 if (message.message.kind === MessageKind.METHOD_NOT_FOUND) return;
421 }
422 SourceSpan span = spanFromNode(node);
423 reportDiagnostic(span, "${magenta('warning:')} $message", false);
424 }
425
426 reportError(Node node, var message) {
427 SourceSpan span = spanFromNode(node);
428 reportDiagnostic(span, "${red('error:')} $message", true);
429 throw new CompilerCancelledException(message.toString());
430 }
431
432 abstract void reportDiagnostic(SourceSpan span, String message, bool fatal);
433
434 SourceSpan spanFromTokens(Token begin, Token end) {
435 if (begin === null || end === null) {
436 // TODO(ahe): We can almost always do better. Often it is only
437 // end that is null. Otherwise, we probably know the current
438 // URI.
439 throw 'cannot find tokens to produce error message';
440 }
441 final startOffset = begin.charOffset;
442 // TODO(ahe): Compute proper end offset in token. Right now we use
443 // the position of the next token. We want to preserve the
444 // invariant that endOffset > startOffset, but for EOF the
445 // charoffset of the next token may be [startOffset]. This can
446 // also happen for synthetized tokens that are produced during
447 // error handling.
448 final endOffset =
449 Math.max((end.next !== null) ? end.next.charOffset : 0, startOffset + 1);
450 assert(endOffset > startOffset);
451 Uri uri = currentElement.getCompilationUnit().script.uri;
452 return new SourceSpan(uri, startOffset, endOffset);
453 }
454
455 SourceSpan spanFromNode(Node node) {
456 return spanFromTokens(node.getBeginToken(), node.getEndToken());
457 }
458
459 SourceSpan spanFromElement(Element element) {
460 if (element.position() === null) {
461 // Sometimes, the backend fakes up elements that have no
462 // position. So we use the enclosing element instead. It is
463 // not a good error location, but cancel really is "internal
464 // error" or "not implemented yet", so the vicinity is good
465 // enough for now.
466 element = element.enclosingElement;
467 // TODO(ahe): I plan to overhaul this infrastructure anyways.
468 }
469 if (element === null) {
470 element = currentElement;
471 }
472 Token position = element.position();
473 if (position === null) {
474 // TODO(ahe): Find the enclosing library.
475 return const SourceSpan(null, null, null);
476 }
477 return spanFromTokens(position, position);
478 }
479
480 Script readScript(Uri uri, [ScriptTag node]) {
481 unimplemented('Compiler.readScript');
482 }
483
484 String get legDirectory() {
485 unimplemented('Compiler.legDirectory');
486 }
487
488 Element findHelper(SourceString name) => jsHelperLibrary.find(name);
489
490 bool get isMockCompilation() => false;
491 }
492
493 class CompilerTask {
494 final Compiler compiler;
495 final Stopwatch watch;
496
497 CompilerTask(this.compiler) : watch = new Stopwatch();
498
499 String get name() => 'Unknown task';
500 int get timing() => watch.elapsedInMs();
501
502 measure(Function action) {
503 // TODO(kasperl): Do we have to worry about exceptions here?
504 CompilerTask previous = compiler.measuredTask;
505 compiler.measuredTask = this;
506 if (previous !== null) previous.watch.stop();
507 watch.start();
508 var result = action();
509 watch.stop();
510 if (previous !== null) previous.watch.start();
511 compiler.measuredTask = previous;
512 return result;
513 }
514 }
515
516 class CompilerCancelledException implements Exception {
517 final String reason;
518 CompilerCancelledException(this.reason);
519
520 String toString() {
521 String banner = 'compiler cancelled';
522 return (reason !== null) ? '$banner: $reason' : '$banner';
523 }
524 }
525
526 interface Tracer default LTracer {
527 const Tracer();
528 final bool enabled;
529 void traceCompilation(String methodName);
530 void traceGraph(String name, var graph);
531 void close();
532 }
533
534 // TODO(ahe): Remove when the VM supports implicit interfaces.
535 class LTracer implements Tracer {
536 const LTracer();
537 final bool enabled = false;
538 void traceCompilation(String methodName) {
539 }
540 void traceGraph(String name, var graph) {
541 }
542 void close() {
543 }
544 }
545
546 class SourceSpan {
547 final Uri uri;
548 final int begin;
549 final int end;
550
551 const SourceSpan(this.uri, this.begin, this.end);
552 }
OLDNEW
« no previous file with comments | « frog/leg/compile_time_constants.dart ('k') | frog/leg/dart2js.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698