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 library js_backend.backend; | 5 library js_backend.backend; |
6 | 6 |
7 import 'dart:async' show Future; | 7 import 'dart:async' show Future; |
8 | 8 |
9 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; | 9 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; |
10 | 10 |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 | 330 |
331 /// If [true], the compiler will emit code that logs whenever a method is | 331 /// If [true], the compiler will emit code that logs whenever a method is |
332 /// called. When TRACE_METHOD is 'console' this will be logged | 332 /// called. When TRACE_METHOD is 'console' this will be logged |
333 /// directly in the JavaScript console. When TRACE_METHOD is 'post' the | 333 /// directly in the JavaScript console. When TRACE_METHOD is 'post' the |
334 /// information will be sent to a server via a POST request. | 334 /// information will be sent to a server via a POST request. |
335 static const String TRACE_METHOD = const String.fromEnvironment('traceCalls'); | 335 static const String TRACE_METHOD = const String.fromEnvironment('traceCalls'); |
336 static const bool TRACE_CALLS = | 336 static const bool TRACE_CALLS = |
337 TRACE_METHOD == 'post' || TRACE_METHOD == 'console'; | 337 TRACE_METHOD == 'post' || TRACE_METHOD == 'console'; |
338 MethodElement traceHelper; | 338 MethodElement traceHelper; |
339 | 339 |
340 TypeMask get stringType => compiler.commonMasks.stringType; | 340 TypeMask get stringType => compiler.closedWorld.commonMasks.stringType; |
341 TypeMask get doubleType => compiler.commonMasks.doubleType; | 341 TypeMask get doubleType => compiler.closedWorld.commonMasks.doubleType; |
342 TypeMask get intType => compiler.commonMasks.intType; | 342 TypeMask get intType => compiler.closedWorld.commonMasks.intType; |
343 TypeMask get uint32Type => compiler.commonMasks.uint32Type; | 343 TypeMask get uint32Type => compiler.closedWorld.commonMasks.uint32Type; |
344 TypeMask get uint31Type => compiler.commonMasks.uint31Type; | 344 TypeMask get uint31Type => compiler.closedWorld.commonMasks.uint31Type; |
345 TypeMask get positiveIntType => compiler.commonMasks.positiveIntType; | 345 TypeMask get positiveIntType => |
346 TypeMask get numType => compiler.commonMasks.numType; | 346 compiler.closedWorld.commonMasks.positiveIntType; |
347 TypeMask get boolType => compiler.commonMasks.boolType; | 347 TypeMask get numType => compiler.closedWorld.commonMasks.numType; |
348 TypeMask get dynamicType => compiler.commonMasks.dynamicType; | 348 TypeMask get boolType => compiler.closedWorld.commonMasks.boolType; |
349 TypeMask get nullType => compiler.commonMasks.nullType; | 349 TypeMask get dynamicType => compiler.closedWorld.commonMasks.dynamicType; |
| 350 TypeMask get nullType => compiler.closedWorld.commonMasks.nullType; |
350 TypeMask get emptyType => const TypeMask.nonNullEmpty(); | 351 TypeMask get emptyType => const TypeMask.nonNullEmpty(); |
351 TypeMask get nonNullType => compiler.commonMasks.nonNullType; | 352 TypeMask get nonNullType => compiler.closedWorld.commonMasks.nonNullType; |
352 | 353 |
353 TypeMask _indexablePrimitiveTypeCache; | 354 TypeMask _indexablePrimitiveTypeCache; |
354 TypeMask get indexablePrimitiveType { | 355 TypeMask get indexablePrimitiveType { |
355 if (_indexablePrimitiveTypeCache == null) { | 356 if (_indexablePrimitiveTypeCache == null) { |
356 _indexablePrimitiveTypeCache = new TypeMask.nonNullSubtype( | 357 _indexablePrimitiveTypeCache = new TypeMask.nonNullSubtype( |
357 helpers.jsIndexableClass, compiler.closedWorld); | 358 helpers.jsIndexableClass, compiler.closedWorld); |
358 } | 359 } |
359 return _indexablePrimitiveTypeCache; | 360 return _indexablePrimitiveTypeCache; |
360 } | 361 } |
361 | 362 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 | 513 |
513 /// True if a core-library function requires the preamble file to function. | 514 /// True if a core-library function requires the preamble file to function. |
514 bool requiresPreamble = false; | 515 bool requiresPreamble = false; |
515 | 516 |
516 /// True if the html library has been loaded. | 517 /// True if the html library has been loaded. |
517 bool htmlLibraryIsLoaded = false; | 518 bool htmlLibraryIsLoaded = false; |
518 | 519 |
519 /// True when we enqueue the loadLibrary code. | 520 /// True when we enqueue the loadLibrary code. |
520 bool isLoadLibraryFunctionResolved = false; | 521 bool isLoadLibraryFunctionResolved = false; |
521 | 522 |
| 523 /// `true` if access to [BackendHelpers.invokeOnMethod] is supported. |
| 524 bool hasInvokeOnSupport = false; |
| 525 |
522 /// List of constants from metadata. If metadata must be preserved, | 526 /// List of constants from metadata. If metadata must be preserved, |
523 /// these constants must be registered. | 527 /// these constants must be registered. |
524 final List<Dependency> metadataConstants = <Dependency>[]; | 528 final List<Dependency> metadataConstants = <Dependency>[]; |
525 | 529 |
526 /// Set of elements for which metadata has been registered as dependencies. | 530 /// Set of elements for which metadata has been registered as dependencies. |
527 final Set<Element> _registeredMetadata = new Set<Element>(); | 531 final Set<Element> _registeredMetadata = new Set<Element>(); |
528 | 532 |
529 /// List of elements that the user has requested for reflection. | 533 /// List of elements that the user has requested for reflection. |
530 final Set<Element> targetsUsed = new Set<Element>(); | 534 final Set<Element> targetsUsed = new Set<Element>(); |
531 | 535 |
(...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1482 | 1486 |
1483 enqueue(helpers.startRootIsolate); | 1487 enqueue(helpers.startRootIsolate); |
1484 enqueue(helpers.currentIsolate); | 1488 enqueue(helpers.currentIsolate); |
1485 enqueue(helpers.callInIsolate); | 1489 enqueue(helpers.callInIsolate); |
1486 } else { | 1490 } else { |
1487 enqueuer.addToWorkList(helpers.startRootIsolate); | 1491 enqueuer.addToWorkList(helpers.startRootIsolate); |
1488 } | 1492 } |
1489 } | 1493 } |
1490 | 1494 |
1491 bool classNeedsRti(ClassElement cls) { | 1495 bool classNeedsRti(ClassElement cls) { |
1492 if (compiler.enabledRuntimeType) return true; | 1496 if (compiler.resolverWorld.hasRuntimeTypeSupport) return true; |
1493 return rti.classesNeedingRti.contains(cls.declaration); | 1497 return rti.classesNeedingRti.contains(cls.declaration); |
1494 } | 1498 } |
1495 | 1499 |
1496 bool classNeedsRtiField(ClassElement cls) { | 1500 bool classNeedsRtiField(ClassElement cls) { |
1497 if (cls.rawType.typeArguments.isEmpty) return false; | 1501 if (cls.rawType.typeArguments.isEmpty) return false; |
1498 if (compiler.enabledRuntimeType) return true; | 1502 if (compiler.resolverWorld.hasRuntimeTypeSupport) return true; |
1499 return rti.classesNeedingRti.contains(cls.declaration); | 1503 return rti.classesNeedingRti.contains(cls.declaration); |
1500 } | 1504 } |
1501 | 1505 |
1502 bool isComplexNoSuchMethod(FunctionElement element) => | 1506 bool isComplexNoSuchMethod(FunctionElement element) => |
1503 noSuchMethodRegistry.isComplex(element); | 1507 noSuchMethodRegistry.isComplex(element); |
1504 | 1508 |
1505 bool isDefaultEqualityImplementation(Element element) { | 1509 bool isDefaultEqualityImplementation(Element element) { |
1506 assert(element.name == '=='); | 1510 assert(element.name == '=='); |
1507 ClassElement classElement = element.enclosingClass; | 1511 ClassElement classElement = element.enclosingClass; |
1508 return classElement == coreClasses.objectClass || | 1512 return classElement == coreClasses.objectClass || |
1509 classElement == helpers.jsInterceptorClass || | 1513 classElement == helpers.jsInterceptorClass || |
1510 classElement == helpers.jsNullClass; | 1514 classElement == helpers.jsNullClass; |
1511 } | 1515 } |
1512 | 1516 |
1513 bool methodNeedsRti(FunctionElement function) { | 1517 bool methodNeedsRti(FunctionElement function) { |
1514 return rti.methodsNeedingRti.contains(function) || | 1518 return rti.methodsNeedingRti.contains(function) || |
1515 compiler.enabledRuntimeType; | 1519 compiler.resolverWorld.hasRuntimeTypeSupport; |
1516 } | 1520 } |
1517 | 1521 |
1518 /// Enqueue [e] in [enqueuer]. | 1522 /// Enqueue [e] in [enqueuer]. |
1519 /// | 1523 /// |
1520 /// This method calls [registerBackendUse]. | 1524 /// This method calls [registerBackendUse]. |
1521 void enqueue(Enqueuer enqueuer, Element e) { | 1525 void enqueue(Enqueuer enqueuer, Element e) { |
1522 if (e == null) return; | 1526 if (e == null) return; |
1523 registerBackendUse(e); | 1527 registerBackendUse(e); |
1524 enqueuer.addToWorkList(e); | 1528 enqueuer.addToWorkList(e); |
1525 compiler.globalDependencies.registerDependency(e); | 1529 compiler.globalDependencies.registerDependency(e); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1564 for (ClassElement cls in impact.instantiatedClasses) { | 1568 for (ClassElement cls in impact.instantiatedClasses) { |
1565 enqueueClass(enqueuer, cls); | 1569 enqueueClass(enqueuer, cls); |
1566 } | 1570 } |
1567 for (BackendImpact otherImpact in impact.otherImpacts) { | 1571 for (BackendImpact otherImpact in impact.otherImpacts) { |
1568 enqueueImpact(enqueuer, otherImpact); | 1572 enqueueImpact(enqueuer, otherImpact); |
1569 } | 1573 } |
1570 } | 1574 } |
1571 | 1575 |
1572 CodegenEnqueuer get codegenEnqueuer => compiler.enqueuer.codegen; | 1576 CodegenEnqueuer get codegenEnqueuer => compiler.enqueuer.codegen; |
1573 | 1577 |
1574 CodegenEnqueuer createCodegenEnqueuer(Compiler compiler) { | 1578 CodegenEnqueuer createCodegenEnqueuer(CompilerTask task, Compiler compiler) { |
1575 return new CodegenEnqueuer(compiler, const TreeShakingEnqueuerStrategy()); | 1579 return new CodegenEnqueuer( |
| 1580 task, compiler, const TreeShakingEnqueuerStrategy()); |
1576 } | 1581 } |
1577 | 1582 |
1578 WorldImpact codegen(CodegenWorkItem work) { | 1583 WorldImpact codegen(CodegenWorkItem work) { |
1579 Element element = work.element; | 1584 Element element = work.element; |
1580 if (compiler.elementHasCompileTimeError(element)) { | 1585 if (compiler.elementHasCompileTimeError(element)) { |
1581 DiagnosticMessage message = | 1586 DiagnosticMessage message = |
1582 // If there's more than one error, the first is probably most | 1587 // If there's more than one error, the first is probably most |
1583 // informative, as the following errors may be side-effects of the | 1588 // informative, as the following errors may be side-effects of the |
1584 // first error. | 1589 // first error. |
1585 compiler.elementsWithCompileTimeErrors[element].first; | 1590 compiler.elementsWithCompileTimeErrors[element].first; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1639 function = function.withSourceInformation( | 1644 function = function.withSourceInformation( |
1640 sourceInformationStrategy.buildSourceMappedMarker()); | 1645 sourceInformationStrategy.buildSourceMappedMarker()); |
1641 } | 1646 } |
1642 generatedCode[element] = function; | 1647 generatedCode[element] = function; |
1643 WorldImpact worldImpact = | 1648 WorldImpact worldImpact = |
1644 impactTransformer.transformCodegenImpact(work.registry.worldImpact); | 1649 impactTransformer.transformCodegenImpact(work.registry.worldImpact); |
1645 compiler.dumpInfoTask.registerImpact(element, worldImpact); | 1650 compiler.dumpInfoTask.registerImpact(element, worldImpact); |
1646 return worldImpact; | 1651 return worldImpact; |
1647 } | 1652 } |
1648 | 1653 |
1649 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) { | 1654 native.NativeEnqueuer nativeResolutionEnqueuer() { |
1650 return new native.NativeResolutionEnqueuer(compiler); | 1655 return new native.NativeResolutionEnqueuer(compiler); |
1651 } | 1656 } |
1652 | 1657 |
1653 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) { | 1658 native.NativeEnqueuer nativeCodegenEnqueuer() { |
1654 return new native.NativeCodegenEnqueuer(compiler, emitter); | 1659 return new native.NativeCodegenEnqueuer(compiler, emitter); |
1655 } | 1660 } |
1656 | 1661 |
1657 ClassElement defaultSuperclass(ClassElement element) { | 1662 ClassElement defaultSuperclass(ClassElement element) { |
1658 if (isJsInterop(element)) { | 1663 if (isJsInterop(element)) { |
1659 return helpers.jsJavaScriptObjectClass; | 1664 return helpers.jsJavaScriptObjectClass; |
1660 } | 1665 } |
1661 // Native classes inherit from Interceptor. | 1666 // Native classes inherit from Interceptor. |
1662 return isNative(element) | 1667 return isNative(element) |
1663 ? helpers.jsInterceptorClass | 1668 ? helpers.jsInterceptorClass |
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2335 return staticFields; | 2340 return staticFields; |
2336 } | 2341 } |
2337 | 2342 |
2338 /// Called when [enqueuer] is empty, but before it is closed. | 2343 /// Called when [enqueuer] is empty, but before it is closed. |
2339 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) { | 2344 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) { |
2340 // Add elements used synthetically, that is, through features rather than | 2345 // Add elements used synthetically, that is, through features rather than |
2341 // syntax, for instance custom elements. | 2346 // syntax, for instance custom elements. |
2342 // | 2347 // |
2343 // Return early if any elements are added to avoid counting the elements as | 2348 // Return early if any elements are added to avoid counting the elements as |
2344 // due to mirrors. | 2349 // due to mirrors. |
2345 enqueuer.applyImpact(customElementsAnalysis.flush( | |
2346 forResolution: enqueuer.isResolutionQueue)); | |
2347 enqueuer.applyImpact( | 2350 enqueuer.applyImpact( |
| 2351 compiler.impactStrategy, |
| 2352 customElementsAnalysis.flush( |
| 2353 forResolution: enqueuer.isResolutionQueue)); |
| 2354 enqueuer.applyImpact(compiler.impactStrategy, |
2348 lookupMapAnalysis.flush(forResolution: enqueuer.isResolutionQueue)); | 2355 lookupMapAnalysis.flush(forResolution: enqueuer.isResolutionQueue)); |
2349 enqueuer.applyImpact( | 2356 enqueuer.applyImpact(compiler.impactStrategy, |
2350 typeVariableHandler.flush(forResolution: enqueuer.isResolutionQueue)); | 2357 typeVariableHandler.flush(forResolution: enqueuer.isResolutionQueue)); |
2351 | 2358 |
2352 if (!enqueuer.queueIsEmpty) return false; | 2359 if (!enqueuer.queueIsEmpty) return false; |
2353 | 2360 |
2354 noSuchMethodRegistry.onQueueEmpty(); | 2361 noSuchMethodRegistry.onQueueEmpty(); |
2355 if (!enabledNoSuchMethod && | 2362 if (!enabledNoSuchMethod && |
2356 (noSuchMethodRegistry.hasThrowingNoSuchMethod || | 2363 (noSuchMethodRegistry.hasThrowingNoSuchMethod || |
2357 noSuchMethodRegistry.hasComplexNoSuchMethod)) { | 2364 noSuchMethodRegistry.hasComplexNoSuchMethod)) { |
2358 enableNoSuchMethod(enqueuer); | 2365 enableNoSuchMethod(enqueuer); |
2359 enabledNoSuchMethod = true; | 2366 enabledNoSuchMethod = true; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2413 // elements and process these instead. | 2420 // elements and process these instead. |
2414 processMetadata(compiler.enqueuer.resolution.processedElements, | 2421 processMetadata(compiler.enqueuer.resolution.processedElements, |
2415 registerMetadataConstant); | 2422 registerMetadataConstant); |
2416 } else { | 2423 } else { |
2417 for (Dependency dependency in metadataConstants) { | 2424 for (Dependency dependency in metadataConstants) { |
2418 computeImpactForCompileTimeConstant( | 2425 computeImpactForCompileTimeConstant( |
2419 dependency.constant, impactBuilder, enqueuer.isResolutionQueue); | 2426 dependency.constant, impactBuilder, enqueuer.isResolutionQueue); |
2420 } | 2427 } |
2421 metadataConstants.clear(); | 2428 metadataConstants.clear(); |
2422 } | 2429 } |
2423 enqueuer.applyImpact(impactBuilder.flush()); | 2430 enqueuer.applyImpact(compiler.impactStrategy, impactBuilder.flush()); |
2424 } | 2431 } |
2425 return true; | 2432 return true; |
2426 } | 2433 } |
2427 | 2434 |
2428 /// Call [registerMetadataConstant] on all metadata from [elements]. | 2435 /// Call [registerMetadataConstant] on all metadata from [elements]. |
2429 void processMetadata(Iterable<Element> elements, | 2436 void processMetadata(Iterable<Element> elements, |
2430 void onMetadata(MetadataAnnotation metadata)) { | 2437 void onMetadata(MetadataAnnotation metadata)) { |
2431 void processLibraryMetadata(LibraryElement library) { | 2438 void processLibraryMetadata(LibraryElement library) { |
2432 if (_registeredMetadata.add(library)) { | 2439 if (_registeredMetadata.add(library)) { |
2433 library.metadata.forEach(onMetadata); | 2440 library.metadata.forEach(onMetadata); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2538 } | 2545 } |
2539 if (hasNoThrows && !hasNoInline) { | 2546 if (hasNoThrows && !hasNoInline) { |
2540 reporter.internalError( | 2547 reporter.internalError( |
2541 element, "@NoThrows() should always be combined with @NoInline."); | 2548 element, "@NoThrows() should always be combined with @NoInline."); |
2542 } | 2549 } |
2543 if (hasNoSideEffects && !hasNoInline) { | 2550 if (hasNoSideEffects && !hasNoInline) { |
2544 reporter.internalError(element, | 2551 reporter.internalError(element, |
2545 "@NoSideEffects() should always be combined with @NoInline."); | 2552 "@NoSideEffects() should always be combined with @NoInline."); |
2546 } | 2553 } |
2547 if (element == helpers.invokeOnMethod) { | 2554 if (element == helpers.invokeOnMethod) { |
2548 compiler.enabledInvokeOn = true; | 2555 hasInvokeOnSupport = true; |
2549 } | 2556 } |
2550 } | 2557 } |
2551 | 2558 |
2552 /* | 2559 /* |
2553 CodeBuffer codeOf(Element element) { | 2560 CodeBuffer codeOf(Element element) { |
2554 return generatedCode.containsKey(element) | 2561 return generatedCode.containsKey(element) |
2555 ? jsAst.prettyPrint(generatedCode[element], compiler) | 2562 ? jsAst.prettyPrint(generatedCode[element], compiler) |
2556 : null; | 2563 : null; |
2557 } | 2564 } |
2558 */ | 2565 */ |
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3269 ClassElement get mapImplementation => helpers.mapLiteralClass; | 3276 ClassElement get mapImplementation => helpers.mapLiteralClass; |
3270 ClassElement get constMapImplementation => helpers.constMapLiteralClass; | 3277 ClassElement get constMapImplementation => helpers.constMapLiteralClass; |
3271 ClassElement get typeImplementation => helpers.typeLiteralClass; | 3278 ClassElement get typeImplementation => helpers.typeLiteralClass; |
3272 ClassElement get boolImplementation => helpers.jsBoolClass; | 3279 ClassElement get boolImplementation => helpers.jsBoolClass; |
3273 ClassElement get nullImplementation => helpers.jsNullClass; | 3280 ClassElement get nullImplementation => helpers.jsNullClass; |
3274 ClassElement get syncStarIterableImplementation => helpers.syncStarIterable; | 3281 ClassElement get syncStarIterableImplementation => helpers.syncStarIterable; |
3275 ClassElement get asyncFutureImplementation => helpers.futureImplementation; | 3282 ClassElement get asyncFutureImplementation => helpers.futureImplementation; |
3276 ClassElement get asyncStarStreamImplementation => helpers.controllerStream; | 3283 ClassElement get asyncStarStreamImplementation => helpers.controllerStream; |
3277 ClassElement get functionImplementation => helpers.coreClasses.functionClass; | 3284 ClassElement get functionImplementation => helpers.coreClasses.functionClass; |
3278 } | 3285 } |
OLD | NEW |