| 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 class WorkItem { | 5 class WorkItem { |
| 6 final Element element; | 6 final Element element; |
| 7 TreeElements resolutionTree; | 7 TreeElements resolutionTree; |
| 8 bool allowSpeculativeOptimization = true; | 8 bool allowSpeculativeOptimization = true; |
| 9 List<HTypeGuard> guards = const <HTypeGuard>[]; | 9 List<HTypeGuard> guards = const <HTypeGuard>[]; |
| 10 | 10 |
| 11 WorkItem(this.element, this.resolutionTree); | 11 WorkItem(this.element, this.resolutionTree); |
| 12 | 12 |
| 13 bool isAnalyzed() => resolutionTree !== null; | 13 bool isAnalyzed() => resolutionTree !== null; |
| 14 | 14 |
| 15 int hashCode() => element.hashCode(); | 15 int hashCode() => element.hashCode(); |
| 16 | 16 |
| 17 String run(Compiler compiler) { | 17 String run(Compiler compiler) { |
| 18 String code = compiler.universe.generatedCode[element]; | 18 String code = compiler.codegenWorld.generatedCode[element]; |
| 19 if (code !== null) return code; | 19 if (code !== null) return code; |
| 20 try { | 20 try { |
| 21 if (!isAnalyzed()) compiler.analyze(this); | 21 if (!isAnalyzed()) compiler.analyze(this); |
| 22 return compiler.codegen(this); | 22 return compiler.codegen(this); |
| 23 } catch (CompilerCancelledException ex) { | 23 } catch (CompilerCancelledException ex) { |
| 24 throw; | 24 throw; |
| 25 } catch (var ex) { | 25 } catch (var ex) { |
| 26 compiler.unhandledExceptionOnElement(element); | 26 compiler.unhandledExceptionOnElement(element); |
| 27 throw; | 27 throw; |
| 28 } | 28 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 52 optimizer = new SsaOptimizerTask(this); | 52 optimizer = new SsaOptimizerTask(this); |
| 53 generator = new SsaCodeGeneratorTask(this); | 53 generator = new SsaCodeGeneratorTask(this); |
| 54 } | 54 } |
| 55 | 55 |
| 56 String codegen(WorkItem work) { | 56 String codegen(WorkItem work) { |
| 57 HGraph graph = builder.build(work); | 57 HGraph graph = builder.build(work); |
| 58 optimizer.optimize(work, graph); | 58 optimizer.optimize(work, graph); |
| 59 if (work.allowSpeculativeOptimization | 59 if (work.allowSpeculativeOptimization |
| 60 && optimizer.trySpeculativeOptimizations(work, graph)) { | 60 && optimizer.trySpeculativeOptimizations(work, graph)) { |
| 61 String code = generator.generateBailoutMethod(work, graph); | 61 String code = generator.generateBailoutMethod(work, graph); |
| 62 compiler.universe.addBailoutCode(work, code); | 62 compiler.codegenWorld.addBailoutCode(work, code); |
| 63 optimizer.prepareForSpeculativeOptimizations(work, graph); | 63 optimizer.prepareForSpeculativeOptimizations(work, graph); |
| 64 optimizer.optimize(work, graph); | 64 optimizer.optimize(work, graph); |
| 65 } | 65 } |
| 66 return generator.generateMethod(work, graph); | 66 return generator.generateMethod(work, graph); |
| 67 } | 67 } |
| 68 | 68 |
| 69 void processNativeClasses(libraries) { | 69 void processNativeClasses(libraries) { |
| 70 native.processNativeClasses(emitter, libraries); | 70 native.processNativeClasses(emitter, libraries); |
| 71 } | 71 } |
| 72 | 72 |
| 73 void assembleProgram() => emitter.assembleProgram(); | 73 void assembleProgram() => emitter.assembleProgram(); |
| 74 } | 74 } |
| 75 | 75 |
| 76 class Compiler implements DiagnosticListener { | 76 class Compiler implements DiagnosticListener { |
| 77 Queue<WorkItem> codegenQueue; | 77 final Map<String, LibraryElement> libraries; |
| 78 Universe universe; | 78 int nextFreeClassId = 0; |
| 79 World world; | 79 World world; |
| 80 String assembledCode; | 80 String assembledCode; |
| 81 Namer namer; | 81 Namer namer; |
| 82 Types types; | 82 Types types; |
| 83 bool enableTypeAssertions = false; | 83 bool enableTypeAssertions = false; |
| 84 | 84 |
| 85 final Tracer tracer; | 85 final Tracer tracer; |
| 86 | 86 |
| 87 CompilerTask measuredTask; | 87 CompilerTask measuredTask; |
| 88 Element _currentElement; | 88 Element _currentElement; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 EnqueueTask enqueuer; | 128 EnqueueTask enqueuer; |
| 129 | 129 |
| 130 static final SourceString MAIN = const SourceString('main'); | 130 static final SourceString MAIN = const SourceString('main'); |
| 131 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); | 131 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); |
| 132 static final SourceString NO_SUCH_METHOD_EXCEPTION = | 132 static final SourceString NO_SUCH_METHOD_EXCEPTION = |
| 133 const SourceString('NoSuchMethodException'); | 133 const SourceString('NoSuchMethodException'); |
| 134 static final SourceString START_ROOT_ISOLATE = | 134 static final SourceString START_ROOT_ISOLATE = |
| 135 const SourceString('startRootIsolate'); | 135 const SourceString('startRootIsolate'); |
| 136 bool enabledNoSuchMethod = false; | 136 bool enabledNoSuchMethod = false; |
| 137 | 137 |
| 138 bool codegenQueueIsClosed = false; | |
| 139 | |
| 140 Stopwatch codegenProgress; | 138 Stopwatch codegenProgress; |
| 141 | 139 |
| 142 Compiler([this.tracer = const Tracer()]) | 140 Compiler([this.tracer = const Tracer()]) |
| 143 : universe = new Universe(), | 141 : libraries = new Map<String, LibraryElement>(), |
| 144 world = new World(), | 142 world = new World(), |
| 145 codegenQueue = new Queue<WorkItem>(), | |
| 146 codegenProgress = new Stopwatch.start() { | 143 codegenProgress = new Stopwatch.start() { |
| 147 namer = new Namer(this); | 144 namer = new Namer(this); |
| 148 constantHandler = new ConstantHandler(this); | 145 constantHandler = new ConstantHandler(this); |
| 149 scanner = new ScannerTask(this); | 146 scanner = new ScannerTask(this); |
| 150 dietParser = new DietParserTask(this); | 147 dietParser = new DietParserTask(this); |
| 151 parser = new ParserTask(this); | 148 parser = new ParserTask(this); |
| 152 validator = new TreeValidatorTask(this); | 149 validator = new TreeValidatorTask(this); |
| 153 resolver = new ResolverTask(this); | 150 resolver = new ResolverTask(this); |
| 154 checker = new TypeCheckerTask(this); | 151 checker = new TypeCheckerTask(this); |
| 155 backend = new JavaScriptBackend(this); | 152 backend = new JavaScriptBackend(this); |
| 156 enqueuer = new EnqueueTask(this); | 153 enqueuer = new EnqueueTask(this); |
| 157 tasks = [scanner, dietParser, parser, resolver, checker, | 154 tasks = [scanner, dietParser, parser, resolver, checker, |
| 158 constantHandler, enqueuer]; | 155 constantHandler, enqueuer]; |
| 159 } | 156 } |
| 160 | 157 |
| 158 Universe get codegenWorld() => enqueuer.codegen.universe; |
| 159 |
| 160 int getNextFreeClassId() => nextFreeClassId++; |
| 161 |
| 161 void ensure(bool condition) { | 162 void ensure(bool condition) { |
| 162 if (!condition) cancel('failed assertion in leg'); | 163 if (!condition) cancel('failed assertion in leg'); |
| 163 } | 164 } |
| 164 | 165 |
| 165 void unimplemented(String methodName, | 166 void unimplemented(String methodName, |
| 166 [Node node, Token token, HInstruction instruction, | 167 [Node node, Token token, HInstruction instruction, |
| 167 Element element]) { | 168 Element element]) { |
| 168 internalError("$methodName not implemented", | 169 internalError("$methodName not implemented", |
| 169 node, token, instruction, element); | 170 node, token, instruction, element); |
| 170 } | 171 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 } | 228 } |
| 228 tracer.close(); | 229 tracer.close(); |
| 229 log('compilation succeeded'); | 230 log('compilation succeeded'); |
| 230 return true; | 231 return true; |
| 231 } | 232 } |
| 232 | 233 |
| 233 void enableNoSuchMethod(Element element) { | 234 void enableNoSuchMethod(Element element) { |
| 234 if (enabledNoSuchMethod) return; | 235 if (enabledNoSuchMethod) return; |
| 235 if (element.enclosingElement == objectClass) return; | 236 if (element.enclosingElement == objectClass) return; |
| 236 enabledNoSuchMethod = true; | 237 enabledNoSuchMethod = true; |
| 237 enqueuer.registerInvocation(NO_SUCH_METHOD, new Selector.invocation(2)); | 238 enqueuer.codegen.registerInvocation(NO_SUCH_METHOD, |
| 239 new Selector.invocation(2)); |
| 238 } | 240 } |
| 239 | 241 |
| 240 void enableIsolateSupport(LibraryElement element) { | 242 void enableIsolateSupport(LibraryElement element) { |
| 241 isolateLibrary = element; | 243 isolateLibrary = element; |
| 242 addToWorkList(element.find(START_ROOT_ISOLATE)); | 244 enqueuer.codegen.addToWorkList(element.find(START_ROOT_ISOLATE)); |
| 243 } | 245 } |
| 244 | 246 |
| 245 bool hasIsolateSupport() => isolateLibrary !== null; | 247 bool hasIsolateSupport() => isolateLibrary !== null; |
| 246 | 248 |
| 247 void onLibraryLoaded(LibraryElement library, Uri uri) { | 249 void onLibraryLoaded(LibraryElement library, Uri uri) { |
| 248 if (uri.toString() == 'dart:isolate') { | 250 if (uri.toString() == 'dart:isolate') { |
| 249 enableIsolateSupport(library); | 251 enableIsolateSupport(library); |
| 250 } | 252 } |
| 251 if (dynamicClass !== null) { | 253 if (dynamicClass !== null) { |
| 252 // When loading the built-in libraries, dynamicClass is null. We | 254 // When loading the built-in libraries, dynamicClass is null. We |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 // built. So we add the implicit import of coreLibrary now. This | 300 // built. So we add the implicit import of coreLibrary now. This |
| 299 // can be cleaned up when we have proper support for "dart:core" | 301 // can be cleaned up when we have proper support for "dart:core" |
| 300 // and don't need to access it through the field "coreLibrary". | 302 // and don't need to access it through the field "coreLibrary". |
| 301 // TODO(ahe): Clean this up as described above. | 303 // TODO(ahe): Clean this up as described above. |
| 302 scanner.importLibrary(coreImplLibrary, coreLibrary, null); | 304 scanner.importLibrary(coreImplLibrary, coreLibrary, null); |
| 303 scanner.importLibrary(jsHelperLibrary, coreLibrary, null); | 305 scanner.importLibrary(jsHelperLibrary, coreLibrary, null); |
| 304 scanner.importLibrary(interceptorsLibrary, coreLibrary, null); | 306 scanner.importLibrary(interceptorsLibrary, coreLibrary, null); |
| 305 addForeignFunctions(jsHelperLibrary); | 307 addForeignFunctions(jsHelperLibrary); |
| 306 addForeignFunctions(interceptorsLibrary); | 308 addForeignFunctions(interceptorsLibrary); |
| 307 | 309 |
| 308 universe.libraries['dart:core'] = coreLibrary; | 310 libraries['dart:core'] = coreLibrary; |
| 309 universe.libraries['dart:coreimpl'] = coreImplLibrary; | 311 libraries['dart:coreimpl'] = coreImplLibrary; |
| 310 | 312 |
| 311 initializeSpecialClasses(); | 313 initializeSpecialClasses(); |
| 312 } | 314 } |
| 313 | 315 |
| 314 /** Define the JS helper functions in the given library. */ | 316 /** Define the JS helper functions in the given library. */ |
| 315 void addForeignFunctions(LibraryElement library) { | 317 void addForeignFunctions(LibraryElement library) { |
| 316 library.define(new ForeignElement( | 318 library.define(new ForeignElement( |
| 317 const SourceString('JS'), library), this); | 319 const SourceString('JS'), library), this); |
| 318 library.define(new ForeignElement( | 320 library.define(new ForeignElement( |
| 319 const SourceString('UNINTERCEPTED'), library), this); | 321 const SourceString('UNINTERCEPTED'), library), this); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 334 if (main === null) { | 336 if (main === null) { |
| 335 reportFatalError('Could not find $MAIN', mainApp); | 337 reportFatalError('Could not find $MAIN', mainApp); |
| 336 } else { | 338 } else { |
| 337 if (!main.isFunction()) reportFatalError('main is not a function', main); | 339 if (!main.isFunction()) reportFatalError('main is not a function', main); |
| 338 FunctionElement mainMethod = main; | 340 FunctionElement mainMethod = main; |
| 339 FunctionSignature parameters = mainMethod.computeSignature(this); | 341 FunctionSignature parameters = mainMethod.computeSignature(this); |
| 340 parameters.forEachParameter((Element parameter) { | 342 parameters.forEachParameter((Element parameter) { |
| 341 reportFatalError('main cannot have parameters', parameter); | 343 reportFatalError('main cannot have parameters', parameter); |
| 342 }); | 344 }); |
| 343 } | 345 } |
| 344 Collection<LibraryElement> libraries = universe.libraries.getValues(); | 346 Collection<LibraryElement> libraries = libraries.getValues(); |
| 345 backend.processNativeClasses(libraries); | 347 backend.processNativeClasses(libraries); |
| 346 world.populate(this, libraries); | 348 world.populate(this, libraries); |
| 347 addToWorkList(main); | 349 enqueuer.codegen.addToWorkList(main); |
| 348 codegenProgress.reset(); | 350 codegenProgress.reset(); |
| 349 while (!codegenQueue.isEmpty()) { | 351 while (!enqueuer.codegen.queue.isEmpty()) { |
| 350 WorkItem work = codegenQueue.removeLast(); | 352 WorkItem work = enqueuer.codegen.queue.removeLast(); |
| 351 withCurrentElement(work.element, () => work.run(this)); | 353 withCurrentElement(work.element, () => work.run(this)); |
| 352 } | 354 } |
| 353 codegenQueueIsClosed = true; | 355 enqueuer.codegen.queueIsClosed = true; |
| 354 assert(enqueuer.checkNoEnqueuedInvokedInstanceMethods()); | 356 assert(enqueuer.codegen.checkNoEnqueuedInvokedInstanceMethods()); |
| 355 enqueuer.registerFieldClosureInvocations(); | 357 enqueuer.codegen.registerFieldClosureInvocations(); |
| 356 backend.assembleProgram(); | 358 backend.assembleProgram(); |
| 357 if (!codegenQueue.isEmpty()) { | 359 if (!enqueuer.codegen.queue.isEmpty()) { |
| 358 internalErrorOnElement(codegenQueue.first().element, | 360 internalErrorOnElement(enqueuer.codegen.queue.first().element, |
| 359 "work list is not empty"); | 361 "work list is not empty"); |
| 360 } | 362 } |
| 361 } | 363 } |
| 362 | 364 |
| 363 TreeElements analyzeElement(Element element) { | 365 TreeElements analyzeElement(Element element) { |
| 364 assert(parser !== null); | 366 assert(parser !== null); |
| 365 Node tree = parser.parse(element); | 367 Node tree = parser.parse(element); |
| 366 validator.validate(tree); | 368 validator.validate(tree); |
| 367 TreeElements elements = resolver.resolve(element); | 369 TreeElements elements = resolver.resolve(element); |
| 368 checker.check(tree, elements); | 370 checker.check(tree, elements); |
| 369 return elements; | 371 return elements; |
| 370 } | 372 } |
| 371 | 373 |
| 372 TreeElements analyze(WorkItem work) { | 374 TreeElements analyze(WorkItem work) { |
| 373 work.resolutionTree = analyzeElement(work.element); | 375 work.resolutionTree = analyzeElement(work.element); |
| 374 return work.resolutionTree; | 376 return work.resolutionTree; |
| 375 } | 377 } |
| 376 | 378 |
| 377 String codegen(WorkItem work) { | 379 String codegen(WorkItem work) { |
| 378 if (codegenProgress.elapsedInMs() > 500) { | 380 if (codegenProgress.elapsedInMs() > 500) { |
| 379 // TODO(ahe): Add structured diagnostics to the compiler API and | 381 // TODO(ahe): Add structured diagnostics to the compiler API and |
| 380 // use it to separate this from the --verbose option. | 382 // use it to separate this from the --verbose option. |
| 381 log('compiled ${universe.generatedCode.length} methods'); | 383 log('compiled ${codegenWorld.generatedCode.length} methods'); |
| 382 codegenProgress.reset(); | 384 codegenProgress.reset(); |
| 383 } | 385 } |
| 384 if (work.element.kind.category == ElementCategory.VARIABLE) { | 386 if (work.element.kind.category == ElementCategory.VARIABLE) { |
| 385 constantHandler.compileWorkItem(work); | 387 constantHandler.compileWorkItem(work); |
| 386 return null; | 388 return null; |
| 387 } else { | 389 } else { |
| 388 String code = backend.codegen(work); | 390 String code = backend.codegen(work); |
| 389 universe.addGeneratedCode(work, code); | 391 codegenWorld.addGeneratedCode(work, code); |
| 390 return code; | 392 return code; |
| 391 } | 393 } |
| 392 } | 394 } |
| 393 | 395 |
| 394 void addToWorkList(Element element, [TreeElements elements]) { | |
| 395 if (codegenQueueIsClosed) { | |
| 396 internalErrorOnElement(element, "work list is closed"); | |
| 397 } | |
| 398 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) { | |
| 399 registerInstantiatedClass(element.enclosingElement); | |
| 400 } | |
| 401 codegenQueue.add(new WorkItem(element, elements)); | |
| 402 } | |
| 403 | |
| 404 void registerStaticUse(Element element) { | 396 void registerStaticUse(Element element) { |
| 405 addToWorkList(element); | 397 enqueuer.codegen.addToWorkList(element); |
| 406 } | 398 } |
| 407 | 399 |
| 408 void registerGetOfStaticFunction(FunctionElement element) { | 400 void registerGetOfStaticFunction(FunctionElement element) { |
| 409 registerStaticUse(element); | 401 registerStaticUse(element); |
| 410 universe.staticFunctionsNeedingGetter.add(element); | 402 codegenWorld.staticFunctionsNeedingGetter.add(element); |
| 411 } | 403 } |
| 412 | 404 |
| 413 void registerDynamicInvocation(SourceString methodName, Selector selector) { | 405 void registerDynamicInvocation(SourceString methodName, Selector selector) { |
| 414 assert(selector !== null); | 406 assert(selector !== null); |
| 415 enqueuer.registerInvocation(methodName, selector); | 407 enqueuer.codegen.registerInvocation(methodName, selector); |
| 416 } | 408 } |
| 417 | 409 |
| 418 void registerDynamicInvocationOf(Element element) { | 410 void registerDynamicInvocationOf(Element element) { |
| 419 addToWorkList(element); | 411 enqueuer.codegen.addToWorkList(element); |
| 420 } | 412 } |
| 421 | 413 |
| 422 void registerDynamicGetter(SourceString methodName, Selector selector) { | 414 void registerDynamicGetter(SourceString methodName, Selector selector) { |
| 423 enqueuer.registerGetter(methodName, selector); | 415 enqueuer.codegen.registerGetter(methodName, selector); |
| 424 } | 416 } |
| 425 | 417 |
| 426 void registerDynamicSetter(SourceString methodName, Selector selector) { | 418 void registerDynamicSetter(SourceString methodName, Selector selector) { |
| 427 enqueuer.registerSetter(methodName, selector); | 419 enqueuer.codegen.registerSetter(methodName, selector); |
| 428 } | 420 } |
| 429 | 421 |
| 430 void registerInstantiatedClass(ClassElement element) { | 422 void registerInstantiatedClass(ClassElement cls) { |
| 431 universe.instantiatedClasses.add(element); | 423 enqueuer.codegen.registerInstantiatedClass(cls); |
| 432 enqueuer.onRegisterInstantiatedClass(element); | |
| 433 } | 424 } |
| 434 | 425 |
| 435 // TODO(ngeoffray): This should get a type. | 426 // TODO(ngeoffray): This should get a type. |
| 436 void registerIsCheck(Element element) { | 427 void registerIsCheck(Element element) { |
| 437 universe.isChecks.add(element); | 428 codegenWorld.isChecks.add(element); |
| 438 } | 429 } |
| 439 | 430 |
| 440 void resolveClass(ClassElement element) { | 431 void resolveClass(ClassElement element) { |
| 441 withCurrentElement(element, () => resolver.resolveClass(element)); | 432 withCurrentElement(element, () => resolver.resolveClass(element)); |
| 442 } | 433 } |
| 443 | 434 |
| 444 Type resolveTypeAnnotation(Element element, TypeAnnotation annotation) { | 435 Type resolveTypeAnnotation(Element element, TypeAnnotation annotation) { |
| 445 return resolver.resolveTypeAnnotation(element, annotation); | 436 return resolver.resolveTypeAnnotation(element, annotation); |
| 446 } | 437 } |
| 447 | 438 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 } | 578 } |
| 588 } | 579 } |
| 589 | 580 |
| 590 class SourceSpan { | 581 class SourceSpan { |
| 591 final Uri uri; | 582 final Uri uri; |
| 592 final int begin; | 583 final int begin; |
| 593 final int end; | 584 final int end; |
| 594 | 585 |
| 595 const SourceSpan(this.uri, this.begin, this.end); | 586 const SourceSpan(this.uri, this.begin, this.end); |
| 596 } | 587 } |
| OLD | NEW |