| Index: pkg/compiler/lib/src/js_backend/backend.dart
|
| diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
|
| index ea2c88916030260f142b1d217adbe3c91cff5575..606e9a694e4a35d50e9ab5b0d37df65c12feecbc 100644
|
| --- a/pkg/compiler/lib/src/js_backend/backend.dart
|
| +++ b/pkg/compiler/lib/src/js_backend/backend.dart
|
| @@ -112,14 +112,24 @@ class FunctionInlineCache {
|
| final Map<FunctionEntity, int> _cachedDecisions =
|
| new Map<FunctionEntity, int>();
|
|
|
| + /// Checks that [method] is the canonical representative for this method.
|
| + ///
|
| + /// For a [MethodElement] this means it must be the declaration element.
|
| + bool checkFunction(FunctionEntity method) {
|
| + if (method is MethodElement) return method.isDeclaration;
|
| + return true;
|
| + }
|
| +
|
| /// Returns the current cache decision. This should only be used for testing.
|
| - int getCurrentCacheDecisionForTesting(Element element) {
|
| + int getCurrentCacheDecisionForTesting(FunctionEntity element) {
|
| + assert(checkFunction(element));
|
| return _cachedDecisions[element];
|
| }
|
|
|
| // Returns `true`/`false` if we have a cached decision.
|
| // Returns `null` otherwise.
|
| bool canInline(FunctionEntity element, {bool insideLoop}) {
|
| + assert(checkFunction(element));
|
| int decision = _cachedDecisions[element];
|
|
|
| if (decision == null) {
|
| @@ -175,6 +185,7 @@ class FunctionInlineCache {
|
| }
|
|
|
| void markAsInlinable(FunctionEntity element, {bool insideLoop}) {
|
| + assert(checkFunction(element));
|
| int oldDecision = _cachedDecisions[element];
|
|
|
| if (oldDecision == null) {
|
| @@ -230,6 +241,7 @@ class FunctionInlineCache {
|
| }
|
|
|
| void markAsNonInlinable(FunctionEntity element, {bool insideLoop: true}) {
|
| + assert(checkFunction(element));
|
| int oldDecision = _cachedDecisions[element];
|
|
|
| if (oldDecision == null) {
|
| @@ -288,6 +300,7 @@ class FunctionInlineCache {
|
| }
|
|
|
| void markAsMustInline(FunctionEntity element) {
|
| + assert(checkFunction(element));
|
| _cachedDecisions[element] = _mustInline;
|
| }
|
| }
|
| @@ -310,7 +323,7 @@ class JavaScriptBackend {
|
| /// Returns true if the backend supports reflection.
|
| bool get supportsReflection => emitter.supportsReflection;
|
|
|
| - final OptimizerHintsForTests annotations;
|
| + final OptimizerHintsForTests optimizerHints;
|
|
|
| /// Set of classes that need to be considered for reflection although not
|
| /// otherwise visible during resolution.
|
| @@ -478,7 +491,8 @@ class JavaScriptBackend {
|
| bool useNewSourceInfo: false,
|
| bool useKernel: false})
|
| : _rti = new _RuntimeTypes(compiler),
|
| - annotations = new OptimizerHintsForTests(compiler),
|
| + optimizerHints = new OptimizerHintsForTests(
|
| + compiler.elementEnvironment, compiler.commonElements),
|
| this.sourceInformationStrategy = createSourceInformationStrategy(
|
| generateSourceMap: generateSourceMap,
|
| useMultiSourceInfo: useMultiSourceInfo,
|
| @@ -1179,36 +1193,38 @@ class JavaScriptBackend {
|
| }
|
|
|
| /// Process backend specific annotations.
|
| + // TODO(johnniwinther): Merge this with [AnnotationProcessor] and use
|
| + // [ElementEnvironment.getMemberMetadata] in [AnnotationProcessor].
|
| void processAnnotations(
|
| - MemberElement element, ClosedWorldRefiner closedWorldRefiner) {
|
| - if (element.isMalformed) {
|
| + MemberEntity element, ClosedWorldRefiner closedWorldRefiner) {
|
| + if (element is MemberElement && element.isMalformed) {
|
| // Elements that are marked as malformed during parsing or resolution
|
| // might be registered here. These should just be ignored.
|
| return;
|
| }
|
|
|
| if (element.isFunction || element.isConstructor) {
|
| - MethodElement method = element.implementation;
|
| - if (annotations.noInline(method)) {
|
| - inlineCache.markAsNonInlinable(method);
|
| + if (optimizerHints.noInline(element)) {
|
| + inlineCache.markAsNonInlinable(element);
|
| }
|
| }
|
| if (element.isField) return;
|
| - MethodElement method = element;
|
| + FunctionEntity method = element;
|
|
|
| - LibraryElement library = method.library;
|
| - if (!library.isPlatformLibrary && !canLibraryUseNative(library)) return;
|
| + LibraryEntity library = method.library;
|
| + if (library.canonicalUri.scheme != 'dart' &&
|
| + !canLibraryUseNative(library)) {
|
| + return;
|
| + }
|
| bool hasNoInline = false;
|
| bool hasForceInline = false;
|
| bool hasNoThrows = false;
|
| bool hasNoSideEffects = false;
|
| - for (MetadataAnnotation metadata in method.implementation.metadata) {
|
| - metadata.ensureResolved(resolution);
|
| - ConstantValue constantValue =
|
| - compiler.constants.getConstantValue(metadata.constant);
|
| + for (ConstantValue constantValue
|
| + in compiler.elementEnvironment.getMemberMetadata(method)) {
|
| if (!constantValue.isConstructedObject) continue;
|
| ObjectConstantValue value = constantValue;
|
| - ClassElement cls = value.type.element;
|
| + ClassEntity cls = value.type.element;
|
| if (cls == commonElements.forceInlineClass) {
|
| hasForceInline = true;
|
| if (VERBOSE_OPTIMIZER_HINTS) {
|
| @@ -1225,8 +1241,15 @@ class JavaScriptBackend {
|
| inlineCache.markAsNonInlinable(method);
|
| } else if (cls == commonElements.noThrowsClass) {
|
| hasNoThrows = true;
|
| - if (!Elements.isStaticOrTopLevelFunction(method) &&
|
| - !method.isFactoryConstructor) {
|
| + bool isValid = true;
|
| + if (method.isTopLevel) {
|
| + isValid = true;
|
| + } else if (method.isStatic) {
|
| + isValid = true;
|
| + } else if (method is ConstructorEntity && method.isFactoryConstructor) {
|
| + isValid = true;
|
| + }
|
| + if (!isValid) {
|
| reporter.internalError(
|
| method,
|
| "@NoThrows() is currently limited to top-level"
|
|
|