mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:59:41 +00:00
Revert "[dart2js] Simplify noInline / tryInline annotations"
This reverts commit 8bae3a1cfd
.
There are versioning issues that need to be addressed.
TBR=kevmoo@google.com
Change-Id: Ia82e94f127523db650e4df03af1179ef94463bee
Reviewed-on: https://dart-review.googlesource.com/76564
Reviewed-by: Stephen Adams <sra@google.com>
Reviewed-by: Kevin Moore <kevmoo@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
parent
2c82a400e8
commit
ded73cdd08
|
@ -502,14 +502,14 @@ abstract class KCommonElements implements CommonElements {
|
|||
|
||||
ClassEntity get forceInlineClass;
|
||||
|
||||
ClassEntity get pragmaClass;
|
||||
FieldEntity get pragmaClassNameField;
|
||||
FieldEntity get pragmaClassOptionsField;
|
||||
|
||||
bool isCreateInvocationMirrorHelper(MemberEntity member);
|
||||
|
||||
bool isSymbolValidatedConstructor(ConstructorEntity element);
|
||||
|
||||
ClassEntity get metaNoInlineClass;
|
||||
|
||||
ClassEntity get metaTryInlineClass;
|
||||
|
||||
/// Returns `true` if [function] is allowed to be external.
|
||||
///
|
||||
/// This returns `true` for foreign helpers, from environment constructors and
|
||||
|
@ -1321,18 +1321,6 @@ class CommonElementsImpl
|
|||
ClassEntity get forceInlineClass =>
|
||||
_forceInlineClass ??= _findHelperClass('ForceInline');
|
||||
|
||||
ClassEntity _pragmaClass;
|
||||
ClassEntity get pragmaClass =>
|
||||
_pragmaClass ??= _findClass(coreLibrary, 'pragma');
|
||||
|
||||
FieldEntity _pragmaClassNameField;
|
||||
FieldEntity get pragmaClassNameField =>
|
||||
_pragmaClassNameField ??= _findClassMember(pragmaClass, 'name');
|
||||
|
||||
FieldEntity _pragmaClassOptionsField;
|
||||
FieldEntity get pragmaClassOptionsField =>
|
||||
_pragmaClassOptionsField ??= _findClassMember(pragmaClass, 'options');
|
||||
|
||||
ClassEntity _jsInvocationMirrorClass;
|
||||
ClassEntity get jsInvocationMirrorClass =>
|
||||
_jsInvocationMirrorClass ??= _findHelperClass('JSInvocationMirror');
|
||||
|
@ -1710,6 +1698,39 @@ class CommonElementsImpl
|
|||
return _expectAssumeDynamicClass;
|
||||
}
|
||||
|
||||
static final Uri PACKAGE_META_DART2JS =
|
||||
new Uri(scheme: 'package', path: 'meta/dart2js.dart');
|
||||
|
||||
bool _metaAnnotationChecked = false;
|
||||
ClassEntity _metaNoInlineClass;
|
||||
ClassEntity _metaTryInlineClass;
|
||||
|
||||
void _ensureMetaAnnotations() {
|
||||
if (!_metaAnnotationChecked) {
|
||||
_metaAnnotationChecked = true;
|
||||
LibraryEntity library = _env.lookupLibrary(PACKAGE_META_DART2JS);
|
||||
if (library != null) {
|
||||
_metaNoInlineClass = _env.lookupClass(library, '_NoInline');
|
||||
_metaTryInlineClass = _env.lookupClass(library, '_TryInline');
|
||||
if (_metaNoInlineClass == null || _metaTryInlineClass == null) {
|
||||
// This is not the package you're looking for.
|
||||
_metaNoInlineClass = null;
|
||||
_metaTryInlineClass = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClassEntity get metaNoInlineClass {
|
||||
_ensureMetaAnnotations();
|
||||
return _metaNoInlineClass;
|
||||
}
|
||||
|
||||
ClassEntity get metaTryInlineClass {
|
||||
_ensureMetaAnnotations();
|
||||
return _metaTryInlineClass;
|
||||
}
|
||||
|
||||
bool isForeign(MemberEntity element) => element.library == foreignLibrary;
|
||||
|
||||
/// Returns `true` if [member] is a "foreign helper", that is, a member whose
|
||||
|
|
|
@ -11,6 +11,34 @@ import '../diagnostics/messages.dart';
|
|||
import '../elements/entities.dart';
|
||||
import '../native/native.dart' as native;
|
||||
|
||||
const VERBOSE_OPTIMIZER_HINTS = false;
|
||||
|
||||
/// Returns `true` if inlining is disabled for [element].
|
||||
bool _noInline(KElementEnvironment elementEnvironment,
|
||||
KCommonElements commonElements, MemberEntity element) {
|
||||
if (_hasAnnotation(
|
||||
elementEnvironment, element, commonElements.metaNoInlineClass)) {
|
||||
return true;
|
||||
}
|
||||
if (_hasAnnotation(
|
||||
elementEnvironment, element, commonElements.expectNoInlineClass)) {
|
||||
// TODO(floitsch): restrict to elements from the test directory.
|
||||
return true;
|
||||
}
|
||||
return _hasAnnotation(
|
||||
elementEnvironment, element, commonElements.noInlineClass);
|
||||
}
|
||||
|
||||
/// Returns `true` if inlining is requested for [element].
|
||||
bool _tryInline(KElementEnvironment elementEnvironment,
|
||||
KCommonElements commonElements, MemberEntity element) {
|
||||
if (_hasAnnotation(
|
||||
elementEnvironment, element, commonElements.metaTryInlineClass)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns `true` if parameter and returns types should be trusted for
|
||||
/// [element].
|
||||
bool _trustTypeAnnotations(KElementEnvironment elementEnvironment,
|
||||
|
@ -52,7 +80,7 @@ AnnotationsData processAnnotations(
|
|||
|
||||
void processMemberAnnotations(MemberEntity element) {
|
||||
bool hasNoInline = false;
|
||||
bool hasTryInline = false;
|
||||
bool hasForceInline = false;
|
||||
|
||||
if (_trustTypeAnnotations(elementEnvironment, commonElements, element)) {
|
||||
annotationsDataBuilder.registerTrustTypeAnnotations(element);
|
||||
|
@ -62,107 +90,93 @@ AnnotationsData processAnnotations(
|
|||
annotationsDataBuilder.registerAssumeDynamic(element);
|
||||
}
|
||||
|
||||
// TODO(sra): Check for inappropriate annotations on fields.
|
||||
if (element.isField) return;
|
||||
if (element.isFunction || element.isConstructor) {
|
||||
if (_noInline(elementEnvironment, commonElements, element)) {
|
||||
hasNoInline = true;
|
||||
annotationsDataBuilder.markAsNonInlinable(element);
|
||||
}
|
||||
if (_tryInline(elementEnvironment, commonElements, element)) {
|
||||
hasForceInline = true;
|
||||
if (hasNoInline) {
|
||||
reporter.reportErrorMessage(element, MessageKind.GENERIC,
|
||||
{'text': '@tryInline must not be used with @noInline.'});
|
||||
} else {
|
||||
annotationsDataBuilder.markAsTryInline(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element.isField) return;
|
||||
FunctionEntity method = element;
|
||||
LibraryEntity library = element.library;
|
||||
bool platformAnnotationsAllowed = library.canonicalUri.scheme == 'dart' ||
|
||||
native.maybeEnableNative(library.canonicalUri);
|
||||
|
||||
LibraryEntity library = method.library;
|
||||
if (library.canonicalUri.scheme != 'dart' &&
|
||||
!native.maybeEnableNative(library.canonicalUri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasNoThrows = false;
|
||||
bool hasNoSideEffects = false;
|
||||
|
||||
for (ConstantValue constantValue
|
||||
in elementEnvironment.getMemberMetadata(method)) {
|
||||
if (!constantValue.isConstructedObject) continue;
|
||||
ConstructedConstantValue value = constantValue;
|
||||
ObjectConstantValue value = constantValue;
|
||||
ClassEntity cls = value.type.element;
|
||||
|
||||
if (platformAnnotationsAllowed) {
|
||||
if (cls == commonElements.forceInlineClass) {
|
||||
hasTryInline = true;
|
||||
} else if (cls == commonElements.noInlineClass) {
|
||||
hasNoInline = true;
|
||||
} else if (cls == commonElements.noThrowsClass) {
|
||||
hasNoThrows = true;
|
||||
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"
|
||||
" or static functions and factory constructors.");
|
||||
}
|
||||
annotationsDataBuilder.registerCannotThrow(method);
|
||||
} else if (cls == commonElements.noSideEffectsClass) {
|
||||
hasNoSideEffects = true;
|
||||
annotationsDataBuilder.registerSideEffectsFree(method);
|
||||
if (cls == commonElements.forceInlineClass) {
|
||||
hasForceInline = true;
|
||||
if (VERBOSE_OPTIMIZER_HINTS) {
|
||||
reporter.reportHintMessage(
|
||||
method, MessageKind.GENERIC, {'text': "Must inline"});
|
||||
}
|
||||
}
|
||||
|
||||
if (cls == commonElements.expectNoInlineClass) {
|
||||
annotationsDataBuilder.markAsTryInline(method);
|
||||
} else if (cls == commonElements.noInlineClass) {
|
||||
hasNoInline = true;
|
||||
} else if (cls == commonElements.pragmaClass) {
|
||||
// Recognize:
|
||||
//
|
||||
// @pragma('dart2js:noInline')
|
||||
// @pragma('dart2js:tryInline')
|
||||
//
|
||||
ConstantValue nameValue =
|
||||
value.fields[commonElements.pragmaClassNameField];
|
||||
if (nameValue == null || !nameValue.isString) continue;
|
||||
String name = (nameValue as StringConstantValue).stringValue;
|
||||
if (!name.startsWith('dart2js:')) continue;
|
||||
|
||||
ConstantValue optionsValue =
|
||||
value.fields[commonElements.pragmaClassOptionsField];
|
||||
if (name == 'dart2js:noInline') {
|
||||
if (!optionsValue.isNull) {
|
||||
reporter.reportErrorMessage(element, MessageKind.GENERIC,
|
||||
{'text': "@pragma('$name') annotation does not take options"});
|
||||
}
|
||||
hasNoInline = true;
|
||||
} else if (name == 'dart2js:tryInline') {
|
||||
if (!optionsValue.isNull) {
|
||||
reporter.reportErrorMessage(element, MessageKind.GENERIC,
|
||||
{'text': "@pragma('$name') annotation does not take options"});
|
||||
}
|
||||
hasTryInline = true;
|
||||
} else if (!platformAnnotationsAllowed) {
|
||||
reporter.reportErrorMessage(element, MessageKind.GENERIC,
|
||||
{'text': "Unknown dart2js pragma @pragma('$name')"});
|
||||
} else {
|
||||
// Handle platform-only `@pragma` annotations.
|
||||
if (VERBOSE_OPTIMIZER_HINTS) {
|
||||
reporter.reportHintMessage(
|
||||
method, MessageKind.GENERIC, {'text': "Cannot inline"});
|
||||
}
|
||||
annotationsDataBuilder.markAsNonInlinable(method);
|
||||
} else if (cls == commonElements.noThrowsClass) {
|
||||
hasNoThrows = true;
|
||||
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"
|
||||
" or static functions and factory constructors.");
|
||||
}
|
||||
if (VERBOSE_OPTIMIZER_HINTS) {
|
||||
reporter.reportHintMessage(
|
||||
method, MessageKind.GENERIC, {'text': "Cannot throw"});
|
||||
}
|
||||
annotationsDataBuilder.registerCannotThrow(method);
|
||||
} else if (cls == commonElements.noSideEffectsClass) {
|
||||
hasNoSideEffects = true;
|
||||
if (VERBOSE_OPTIMIZER_HINTS) {
|
||||
reporter.reportHintMessage(
|
||||
method, MessageKind.GENERIC, {'text': "Has no side effects"});
|
||||
}
|
||||
annotationsDataBuilder.registerSideEffectsFree(method);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTryInline && hasNoInline) {
|
||||
reporter.reportErrorMessage(element, MessageKind.GENERIC,
|
||||
{'text': '@tryInline must not be used with @noInline.'});
|
||||
hasTryInline = false;
|
||||
}
|
||||
if (hasNoInline) {
|
||||
annotationsDataBuilder.markAsNonInlinable(method);
|
||||
}
|
||||
if (hasTryInline) {
|
||||
annotationsDataBuilder.markAsTryInline(method);
|
||||
if (hasForceInline && hasNoInline) {
|
||||
reporter.internalError(
|
||||
method, "@ForceInline() must not be used with @NoInline.");
|
||||
}
|
||||
if (hasNoThrows && !hasNoInline) {
|
||||
reporter.internalError(
|
||||
method, "@NoThrows() should always be combined with @noInline.");
|
||||
method, "@NoThrows() should always be combined with @NoInline.");
|
||||
}
|
||||
if (hasNoSideEffects && !hasNoInline) {
|
||||
reporter.internalError(
|
||||
method, "@NoSideEffects() should always be combined with @noInline.");
|
||||
method, "@NoSideEffects() should always be combined with @NoInline.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ library meta_dart2js;
|
|||
///
|
||||
/// @dart2js.noInline
|
||||
/// String text() => 'A String of unusual size';
|
||||
const pragma noInline = const pragma('dart2js:noInline');
|
||||
const _NoInline noInline = const _NoInline();
|
||||
|
||||
/// An annotation for methods method to request that dart2js always inlines the
|
||||
/// method.
|
||||
|
@ -34,4 +34,12 @@ const pragma noInline = const pragma('dart2js:noInline');
|
|||
/// }
|
||||
///
|
||||
/// It is an error to use both `@noInline` and `@tryInline` on the same method.
|
||||
const pragma tryInline = const pragma('dart2js:tryInline');
|
||||
const _TryInline tryInline = const _TryInline();
|
||||
|
||||
class _NoInline {
|
||||
const _NoInline();
|
||||
}
|
||||
|
||||
class _TryInline {
|
||||
const _TryInline();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ main() {
|
|||
compiler.resolutionWorldBuilder.closedWorldForTesting;
|
||||
KElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
|
||||
Expect.isFalse(compiler.compilationFailed, 'Unsuccessful compilation');
|
||||
Expect.isNotNull(closedWorld.commonElements.metaNoInlineClass,
|
||||
'NoInlineClass is unresolved.');
|
||||
Expect.isNotNull(closedWorld.commonElements.metaTryInlineClass,
|
||||
'TryInlineClass is unresolved.');
|
||||
|
||||
void test(String name,
|
||||
{bool expectNoInline: false, bool expectTryInline: false}) {
|
||||
|
|
Loading…
Reference in a new issue