Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 | 5 |
| 6 /** | 6 /** |
| 7 * If true, print a warning for each method that was resolved, but not | 7 * If true, print a warning for each method that was resolved, but not |
| 8 * compiled. | 8 * compiled. |
| 9 */ | 9 */ |
| 10 final bool REPORT_EXCESS_RESOLUTION = false; | 10 final bool REPORT_EXCESS_RESOLUTION = false; |
| 11 | 11 |
| 12 /** | |
| 13 * If true, trace information on pass2 optimizations. | |
| 14 */ | |
| 15 final bool REPORT_PASS2_OPTIMIZATIONS = false; | |
| 16 | |
| 12 class WorkItem { | 17 class WorkItem { |
| 13 final Element element; | 18 final Element element; |
| 14 TreeElements resolutionTree; | 19 TreeElements resolutionTree; |
| 15 bool allowSpeculativeOptimization = true; | 20 bool allowSpeculativeOptimization = true; |
| 16 List<HTypeGuard> guards = const <HTypeGuard>[]; | 21 List<HTypeGuard> guards = const <HTypeGuard>[]; |
| 17 | 22 |
| 18 WorkItem(this.element, this.resolutionTree); | 23 WorkItem(this.element, this.resolutionTree); |
| 19 | 24 |
| 20 bool isAnalyzed() => resolutionTree !== null; | 25 bool isAnalyzed() => resolutionTree !== null; |
| 21 | 26 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 ScannerTask scanner; | 162 ScannerTask scanner; |
| 158 DietParserTask dietParser; | 163 DietParserTask dietParser; |
| 159 ParserTask parser; | 164 ParserTask parser; |
| 160 TreeValidatorTask validator; | 165 TreeValidatorTask validator; |
| 161 UnparseValidator unparseValidator; | 166 UnparseValidator unparseValidator; |
| 162 ResolverTask resolver; | 167 ResolverTask resolver; |
| 163 TypeCheckerTask checker; | 168 TypeCheckerTask checker; |
| 164 Backend backend; | 169 Backend backend; |
| 165 ConstantHandler constantHandler; | 170 ConstantHandler constantHandler; |
| 166 EnqueueTask enqueuer; | 171 EnqueueTask enqueuer; |
| 172 int pass = 1; | |
|
ngeoffray
2012/06/14 12:42:24
This field name is a little too generic for my tas
Søren Gjesse
2012/06/15 09:25:02
Changed it to phase and added constants for each p
| |
| 167 | 173 |
| 168 static final SourceString MAIN = const SourceString('main'); | 174 static final SourceString MAIN = const SourceString('main'); |
| 169 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); | 175 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); |
| 170 static final SourceString NO_SUCH_METHOD_EXCEPTION = | 176 static final SourceString NO_SUCH_METHOD_EXCEPTION = |
| 171 const SourceString('NoSuchMethodException'); | 177 const SourceString('NoSuchMethodException'); |
| 172 static final SourceString START_ROOT_ISOLATE = | 178 static final SourceString START_ROOT_ISOLATE = |
| 173 const SourceString('startRootIsolate'); | 179 const SourceString('startRootIsolate'); |
| 174 bool enabledNoSuchMethod = false; | 180 bool enabledNoSuchMethod = false; |
| 175 | 181 |
| 176 Stopwatch codegenProgress; | 182 Stopwatch codegenProgress; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 193 resolver = new ResolverTask(this); | 199 resolver = new ResolverTask(this); |
| 194 checker = new TypeCheckerTask(this); | 200 checker = new TypeCheckerTask(this); |
| 195 backend = emitJavascript ? | 201 backend = emitJavascript ? |
| 196 new JavaScriptBackend(this) : new dart_backend.DartBackend(this); | 202 new JavaScriptBackend(this) : new dart_backend.DartBackend(this); |
| 197 enqueuer = new EnqueueTask(this); | 203 enqueuer = new EnqueueTask(this); |
| 198 tasks = [scanner, dietParser, parser, resolver, checker, | 204 tasks = [scanner, dietParser, parser, resolver, checker, |
| 199 unparseValidator, constantHandler, enqueuer]; | 205 unparseValidator, constantHandler, enqueuer]; |
| 200 tasks.addAll(backend.tasks); | 206 tasks.addAll(backend.tasks); |
| 201 } | 207 } |
| 202 | 208 |
| 209 Universe get resolverWorld() => enqueuer.resolution.universe; | |
| 203 Universe get codegenWorld() => enqueuer.codegen.universe; | 210 Universe get codegenWorld() => enqueuer.codegen.universe; |
| 204 | 211 |
| 205 int getNextFreeClassId() => nextFreeClassId++; | 212 int getNextFreeClassId() => nextFreeClassId++; |
| 206 | 213 |
| 207 void ensure(bool condition) { | 214 void ensure(bool condition) { |
| 208 if (!condition) cancel('failed assertion in leg'); | 215 if (!condition) cancel('failed assertion in leg'); |
| 209 } | 216 } |
| 210 | 217 |
| 211 void unimplemented(String methodName, | 218 void unimplemented(String methodName, |
| 212 [Node node, Token token, HInstruction instruction, | 219 [Node node, Token token, HInstruction instruction, |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 // should know this. | 420 // should know this. |
| 414 world.populate(this, libraries.getValues()); | 421 world.populate(this, libraries.getValues()); |
| 415 | 422 |
| 416 log('Resolving...'); | 423 log('Resolving...'); |
| 417 backend.enqueueHelpers(enqueuer.resolution); | 424 backend.enqueueHelpers(enqueuer.resolution); |
| 418 processQueue(enqueuer.resolution, main); | 425 processQueue(enqueuer.resolution, main); |
| 419 log('Resolved ${enqueuer.resolution.resolvedElements.length} elements.'); | 426 log('Resolved ${enqueuer.resolution.resolvedElements.length} elements.'); |
| 420 | 427 |
| 421 log('Compiling...'); | 428 log('Compiling...'); |
| 422 processQueue(enqueuer.codegen, main); | 429 processQueue(enqueuer.codegen, main); |
| 430 log("Recompiling ${enqueuer.codegen.recompilationCandidates.length} " | |
| 431 "methods..."); | |
| 432 processRecompilationQueue(enqueuer.codegen); | |
| 423 log('Compiled ${codegenWorld.generatedCode.length} methods.'); | 433 log('Compiled ${codegenWorld.generatedCode.length} methods.'); |
| 424 | 434 |
| 425 backend.assembleProgram(); | 435 backend.assembleProgram(); |
| 426 | 436 |
| 427 checkQueues(); | 437 checkQueues(); |
| 428 } | 438 } |
| 429 | 439 |
| 430 processQueue(Enqueuer world, Element main) { | 440 processQueue(Enqueuer world, Element main) { |
| 431 backend.processNativeClasses(world, libraries.getValues()); | 441 backend.processNativeClasses(world, libraries.getValues()); |
| 432 world.addToWorkList(main); | 442 world.addToWorkList(main); |
| 433 codegenProgress.reset(); | 443 codegenProgress.reset(); |
| 434 world.forEach((WorkItem work) { | 444 world.forEach((WorkItem work) { |
| 435 withCurrentElement(work.element, () => work.run(this, world)); | 445 withCurrentElement(work.element, () => work.run(this, world)); |
| 436 }); | 446 }); |
| 437 world.queueIsClosed = true; | 447 world.queueIsClosed = true; |
| 438 assert(world.checkNoEnqueuedInvokedInstanceMethods()); | 448 assert(world.checkNoEnqueuedInvokedInstanceMethods()); |
| 439 world.registerFieldClosureInvocations(); | 449 world.registerFieldClosureInvocations(); |
| 440 } | 450 } |
| 441 | 451 |
| 452 processRecompilationQueue(Enqueuer world) { | |
| 453 pass = 2; | |
| 454 while (!world.recompilationCandidates.isEmpty()) { | |
| 455 WorkItem work = world.recompilationCandidates.next(); | |
| 456 var oldCode = world.universe.generatedCode[work.element]; | |
| 457 world.universe.generatedCode.remove(work.element); | |
| 458 withCurrentElement(work.element, () => work.run(this, world)); | |
| 459 var newCode = world.universe.generatedCode[work.element]; | |
| 460 if (REPORT_PASS2_OPTIMIZATIONS && newCode != oldCode) { | |
| 461 log("Pass 2 optimization:"); | |
| 462 log("Before:\n$oldCode"); | |
| 463 log("After:\n$newCode"); | |
| 464 } | |
| 465 } | |
| 466 } | |
| 467 | |
| 442 /** | 468 /** |
| 443 * Perform various checks of the queues. This includes checking that | 469 * Perform various checks of the queues. This includes checking that |
| 444 * the queues are empty (nothing was added after we stopped | 470 * the queues are empty (nothing was added after we stopped |
| 445 * processing the quese). Also compute the number of methods that | 471 * processing the quese). Also compute the number of methods that |
| 446 * were resolved, but not compiled (aka excess resolution). | 472 * were resolved, but not compiled (aka excess resolution). |
| 447 */ | 473 */ |
| 448 checkQueues() { | 474 checkQueues() { |
| 449 for (var world in [enqueuer.resolution, enqueuer.codegen]) { | 475 for (var world in [enqueuer.resolution, enqueuer.codegen]) { |
| 450 world.forEach((WorkItem work) { | 476 world.forEach((WorkItem work) { |
| 451 internalErrorOnElement(work.element, "Work list is not empty."); | 477 internalErrorOnElement(work.element, "Work list is not empty."); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 result = analyzeElement(element); | 543 result = analyzeElement(element); |
| 518 enqueuer.resolution.resolvedElements[element] = result; | 544 enqueuer.resolution.resolvedElements[element] = result; |
| 519 return result; | 545 return result; |
| 520 } | 546 } |
| 521 | 547 |
| 522 String codegen(WorkItem work, Enqueuer world) { | 548 String codegen(WorkItem work, Enqueuer world) { |
| 523 if (world !== enqueuer.codegen) return null; | 549 if (world !== enqueuer.codegen) return null; |
| 524 if (codegenProgress.elapsedInMs() > 500) { | 550 if (codegenProgress.elapsedInMs() > 500) { |
| 525 // TODO(ahe): Add structured diagnostics to the compiler API and | 551 // TODO(ahe): Add structured diagnostics to the compiler API and |
| 526 // use it to separate this from the --verbose option. | 552 // use it to separate this from the --verbose option. |
| 527 log('Compiled ${codegenWorld.generatedCode.length} methods.'); | 553 log('Compiled ${codegenWorld.generatedCode.length} methods.'); |
|
ahe
2012/06/14 13:23:54
I think you may have broken this message. I think
Søren Gjesse
2012/06/15 09:25:02
Updated to report something more useful. Made the
| |
| 528 codegenProgress.reset(); | 554 codegenProgress.reset(); |
| 529 } | 555 } |
| 530 if (work.element.kind.category == ElementCategory.VARIABLE) { | 556 if (work.element.kind.category == ElementCategory.VARIABLE) { |
| 531 constantHandler.compileWorkItem(work); | 557 constantHandler.compileWorkItem(work); |
| 532 return null; | 558 return null; |
| 533 } else { | 559 } else { |
| 534 String code = backend.codegen(work); | 560 String code = backend.codegen(work); |
| 535 codegenWorld.addGeneratedCode(work, code); | 561 codegenWorld.addGeneratedCode(work, code); |
| 536 return code; | 562 return code; |
| 537 } | 563 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 576 if (message is TypeWarning) { | 602 if (message is TypeWarning) { |
| 577 // TODO(ahe): Don't supress these warning when the type checker | 603 // TODO(ahe): Don't supress these warning when the type checker |
| 578 // is more complete. | 604 // is more complete. |
| 579 if (message.message.kind === MessageKind.NOT_ASSIGNABLE) return; | 605 if (message.message.kind === MessageKind.NOT_ASSIGNABLE) return; |
| 580 if (message.message.kind === MessageKind.MISSING_RETURN) return; | 606 if (message.message.kind === MessageKind.MISSING_RETURN) return; |
| 581 if (message.message.kind === MessageKind.MAYBE_MISSING_RETURN) return; | 607 if (message.message.kind === MessageKind.MAYBE_MISSING_RETURN) return; |
| 582 if (message.message.kind === MessageKind.ADDITIONAL_ARGUMENT) return; | 608 if (message.message.kind === MessageKind.ADDITIONAL_ARGUMENT) return; |
| 583 if (message.message.kind === MessageKind.METHOD_NOT_FOUND) return; | 609 if (message.message.kind === MessageKind.METHOD_NOT_FOUND) return; |
| 584 } | 610 } |
| 585 SourceSpan span = spanFromNode(node); | 611 SourceSpan span = spanFromNode(node); |
| 612 | |
| 586 reportDiagnostic(span, "${magenta('warning:')} $message", false); | 613 reportDiagnostic(span, "${magenta('warning:')} $message", false); |
| 587 } | 614 } |
| 588 | 615 |
| 589 reportError(Node node, var message) { | 616 reportError(Node node, var message) { |
| 590 SourceSpan span = spanFromNode(node); | 617 SourceSpan span = spanFromNode(node); |
| 591 reportDiagnostic(span, "${red('error:')} $message", true); | 618 reportDiagnostic(span, "${red('error:')} $message", true); |
| 592 throw new CompilerCancelledException(message.toString()); | 619 throw new CompilerCancelledException(message.toString()); |
| 593 } | 620 } |
| 594 | 621 |
| 595 abstract void reportDiagnostic(SourceSpan span, String message, bool fatal); | 622 abstract void reportDiagnostic(SourceSpan span, String message, bool fatal); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 // invariant that endOffset > beginOffset, but for EOF the | 738 // invariant that endOffset > beginOffset, but for EOF the |
| 712 // charoffset of the next token may be [beginOffset]. This can | 739 // charoffset of the next token may be [beginOffset]. This can |
| 713 // also happen for synthetized tokens that are produced during | 740 // also happen for synthetized tokens that are produced during |
| 714 // error handling. | 741 // error handling. |
| 715 final endOffset = | 742 final endOffset = |
| 716 Math.max((end.next !== null) ? end.next.charOffset : 0, beginOffset + 1); | 743 Math.max((end.next !== null) ? end.next.charOffset : 0, beginOffset + 1); |
| 717 assert(endOffset > beginOffset); | 744 assert(endOffset > beginOffset); |
| 718 return f(beginOffset, endOffset); | 745 return f(beginOffset, endOffset); |
| 719 } | 746 } |
| 720 } | 747 } |
| OLD | NEW |