blob: cbd3752e8a34d310b532b2ed5d1130b9e310e111 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.js_helpers.impact;
import '../common/names.dart';
import '../compiler.dart' show Compiler;
import '../core_types.dart' show CommonElements;
import '../dart_types.dart' show InterfaceType;
import '../elements/elements.dart' show ClassElement, Element;
import '../universe/selector.dart';
import '../util/enumset.dart';
import 'backend_helpers.dart';
import 'constant_system_javascript.dart';
import 'js_backend.dart';
/// Backend specific features required by a backend impact.
enum BackendFeature {
needToInitializeIsolateAffinityTag,
needToInitializeDispatchProperty,
}
/// A set of JavaScript backend dependencies.
class BackendImpact {
final List<Element> staticUses;
final List<Element> globalUses;
final List<Selector> dynamicUses;
final List<InterfaceType> instantiatedTypes;
final List<ClassElement> instantiatedClasses;
final List<ClassElement> globalClasses;
final List<BackendImpact> otherImpacts;
final EnumSet<BackendFeature> _features;
const BackendImpact(
{this.staticUses: const <Element>[],
this.globalUses: const <Element>[],
this.dynamicUses: const <Selector>[],
this.instantiatedTypes: const <InterfaceType>[],
this.instantiatedClasses: const <ClassElement>[],
this.globalClasses: const <ClassElement>[],
this.otherImpacts: const <BackendImpact>[],
EnumSet<BackendFeature> features: const EnumSet<BackendFeature>.fixed(0)})
: this._features = features;
Iterable<BackendFeature> get features =>
_features.iterable(BackendFeature.values);
}
/// The JavaScript backend dependencies for various features.
class BackendImpacts {
final Compiler compiler;
BackendImpacts(this.compiler);
JavaScriptBackend get backend => compiler.backend;
BackendHelpers get helpers => backend.helpers;
CommonElements get commonElements => compiler.commonElements;
BackendImpact _getRuntimeTypeArgument;
BackendImpact get getRuntimeTypeArgument {
return _getRuntimeTypeArgument ??= new BackendImpact(globalUses: [
helpers.getRuntimeTypeArgument,
helpers.getTypeArgumentByIndex,
]);
}
BackendImpact _computeSignature;
BackendImpact get computeSignature {
return _computeSignature ??= new BackendImpact(globalUses: [
helpers.setRuntimeTypeInfo,
helpers.getRuntimeTypeInfo,
helpers.computeSignature,
helpers.getRuntimeTypeArguments
], otherImpacts: [
listValues
]);
}
BackendImpact _mainWithArguments;
BackendImpact get mainWithArguments {
return _mainWithArguments ??= new BackendImpact(
instantiatedClasses: [helpers.jsArrayClass, helpers.jsStringClass]);
}
BackendImpact _asyncBody;
BackendImpact get asyncBody {
return _asyncBody ??= new BackendImpact(staticUses: [
helpers.asyncHelper,
helpers.syncCompleterConstructor,
helpers.streamIteratorConstructor,
helpers.wrapBody
]);
}
BackendImpact _syncStarBody;
BackendImpact get syncStarBody {
return _syncStarBody ??= new BackendImpact(staticUses: [
helpers.syncStarIterableConstructor,
helpers.endOfIteration,
helpers.yieldStar,
helpers.syncStarUncaughtError
], instantiatedClasses: [
helpers.syncStarIterable
]);
}
BackendImpact _asyncStarBody;
BackendImpact get asyncStarBody {
return _asyncStarBody ??= new BackendImpact(staticUses: [
helpers.asyncStarHelper,
helpers.streamOfController,
helpers.yieldSingle,
helpers.yieldStar,
helpers.asyncStarControllerConstructor,
helpers.streamIteratorConstructor,
helpers.wrapBody
], instantiatedClasses: [
helpers.asyncStarController
]);
}
BackendImpact _typeVariableBoundCheck;
BackendImpact get typeVariableBoundCheck {
return _typeVariableBoundCheck ??= new BackendImpact(
staticUses: [helpers.throwTypeError, helpers.assertIsSubtype]);
}
BackendImpact _abstractClassInstantiation;
BackendImpact get abstractClassInstantiation {
return _abstractClassInstantiation ??= new BackendImpact(
staticUses: [helpers.throwAbstractClassInstantiationError],
otherImpacts: [_needsString('Needed to encode the message.')]);
}
BackendImpact _fallThroughError;
BackendImpact get fallThroughError {
return _fallThroughError ??=
new BackendImpact(staticUses: [helpers.fallThroughError]);
}
BackendImpact _asCheck;
BackendImpact get asCheck {
return _asCheck ??=
new BackendImpact(staticUses: [helpers.throwRuntimeError]);
}
BackendImpact _throwNoSuchMethod;
BackendImpact get throwNoSuchMethod {
return _throwNoSuchMethod ??= new BackendImpact(
instantiatedClasses: compiler.options.useKernel
? [
commonElements.symbolClass,
]
: [],
staticUses: compiler.options.useKernel
? [
helpers.genericNoSuchMethod,
helpers.unresolvedConstructorError,
commonElements.symbolConstructor.declaration,
]
: [
helpers.throwNoSuchMethod,
],
otherImpacts: [
// Also register the types of the arguments passed to this method.
_needsList(
'Needed to encode the arguments for throw NoSuchMethodError.'),
_needsString('Needed to encode the name for throw NoSuchMethodError.')
]);
}
BackendImpact _stringValues;
BackendImpact get stringValues {
return _stringValues ??=
new BackendImpact(instantiatedClasses: [helpers.jsStringClass]);
}
BackendImpact _numValues;
BackendImpact get numValues {
return _numValues ??= new BackendImpact(instantiatedClasses: [
helpers.jsIntClass,
helpers.jsPositiveIntClass,
helpers.jsUInt32Class,
helpers.jsUInt31Class,
helpers.jsNumberClass,
helpers.jsDoubleClass
]);
}
BackendImpact get intValues => numValues;
BackendImpact get doubleValues => numValues;
BackendImpact _boolValues;
BackendImpact get boolValues {
return _boolValues ??=
new BackendImpact(instantiatedClasses: [helpers.jsBoolClass]);
}
BackendImpact _nullValue;
BackendImpact get nullValue {
return _nullValue ??=
new BackendImpact(instantiatedClasses: [helpers.jsNullClass]);
}
BackendImpact _listValues;
BackendImpact get listValues {
return _listValues ??= new BackendImpact(globalClasses: [
helpers.jsArrayClass,
helpers.jsMutableArrayClass,
helpers.jsFixedArrayClass,
helpers.jsExtendableArrayClass,
helpers.jsUnmodifiableArrayClass
]);
}
BackendImpact _throwRuntimeError;
BackendImpact get throwRuntimeError {
return _throwRuntimeError ??= new BackendImpact(
staticUses: compiler.options.useKernel
? [
// TODO(sra): Refactor impacts so that we know which of these
// are called.
helpers.malformedTypeError,
helpers.throwRuntimeError,
]
: [
helpers.throwRuntimeError,
],
otherImpacts: [
// Also register the types of the arguments passed to this method.
stringValues
]);
}
BackendImpact _superNoSuchMethod;
BackendImpact get superNoSuchMethod {
return _superNoSuchMethod ??= new BackendImpact(staticUses: [
helpers.createInvocationMirror,
helpers.objectNoSuchMethod
], otherImpacts: [
_needsInt('Needed to encode the invocation kind of super.noSuchMethod.'),
_needsList('Needed to encode the arguments of super.noSuchMethod.'),
_needsString('Needed to encode the name of super.noSuchMethod.')
]);
}
BackendImpact _constantMapLiteral;
BackendImpact get constantMapLiteral {
if (_constantMapLiteral == null) {
ClassElement find(String name) {
return helpers.find(helpers.jsHelperLibrary, name);
}
_constantMapLiteral = new BackendImpact(instantiatedClasses: [
find(JavaScriptMapConstant.DART_CLASS),
find(JavaScriptMapConstant.DART_PROTO_CLASS),
find(JavaScriptMapConstant.DART_STRING_CLASS),
find(JavaScriptMapConstant.DART_GENERAL_CLASS)
]);
}
return _constantMapLiteral;
}
BackendImpact _symbolConstructor;
BackendImpact get symbolConstructor {
return _symbolConstructor ??=
new BackendImpact(staticUses: [helpers.symbolValidatedConstructor]);
}
BackendImpact _constSymbol;
BackendImpact get constSymbol {
return _constSymbol ??= new BackendImpact(
instantiatedClasses: [commonElements.symbolClass],
staticUses: [commonElements.symbolConstructor.declaration]);
}
/// Helper for registering that `int` is needed.
BackendImpact _needsInt(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
return intValues;
}
/// Helper for registering that `List` is needed.
BackendImpact _needsList(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
return listValues;
}
/// Helper for registering that `String` is needed.
BackendImpact _needsString(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
return stringValues;
}
BackendImpact _assertWithoutMessage;
BackendImpact get assertWithoutMessage {
return _assertWithoutMessage ??=
new BackendImpact(staticUses: [helpers.assertHelper]);
}
BackendImpact _assertWithMessage;
BackendImpact get assertWithMessage {
return _assertWithMessage ??= new BackendImpact(
staticUses: [helpers.assertTest, helpers.assertThrow]);
}
BackendImpact _asyncForIn;
BackendImpact get asyncForIn {
return _asyncForIn ??=
new BackendImpact(staticUses: [helpers.streamIteratorConstructor]);
}
BackendImpact _stringInterpolation;
BackendImpact get stringInterpolation {
return _stringInterpolation ??= new BackendImpact(
dynamicUses: [Selectors.toString_],
staticUses: [helpers.stringInterpolationHelper],
otherImpacts: [_needsString('Strings are created.')]);
}
BackendImpact _stringJuxtaposition;
BackendImpact get stringJuxtaposition {
return _stringJuxtaposition ??= _needsString('String.concat is used.');
}
BackendImpact get nullLiteral => nullValue;
BackendImpact get boolLiteral => boolValues;
BackendImpact get intLiteral => intValues;
BackendImpact get doubleLiteral => doubleValues;
BackendImpact get stringLiteral => stringValues;
BackendImpact _catchStatement;
BackendImpact get catchStatement {
return _catchStatement ??= new BackendImpact(staticUses: [
helpers.exceptionUnwrapper
], instantiatedClasses: [
helpers.jsPlainJavaScriptObjectClass,
helpers.jsUnknownJavaScriptObjectClass
]);
}
BackendImpact _throwExpression;
BackendImpact get throwExpression {
return _throwExpression ??= new BackendImpact(
// We don't know ahead of time whether we will need the throw in a
// statement context or an expression context, so we register both
// here, even though we may not need the throwExpression helper.
staticUses: [
helpers.wrapExceptionHelper,
helpers.throwExpressionHelper
]);
}
BackendImpact _lazyField;
BackendImpact get lazyField {
return _lazyField ??=
new BackendImpact(staticUses: [helpers.cyclicThrowHelper]);
}
BackendImpact _typeLiteral;
BackendImpact get typeLiteral {
return _typeLiteral ??= new BackendImpact(
instantiatedClasses: [backend.backendClasses.typeImplementation],
staticUses: [helpers.createRuntimeType]);
}
BackendImpact _stackTraceInCatch;
BackendImpact get stackTraceInCatch {
return _stackTraceInCatch ??= new BackendImpact(
instantiatedClasses: [helpers.stackTraceClass],
staticUses: [helpers.traceFromException]);
}
BackendImpact _syncForIn;
BackendImpact get syncForIn {
return _syncForIn ??= new BackendImpact(
// The SSA builder recognizes certain for-in loops and can generate
// calls to throwConcurrentModificationError.
staticUses: [helpers.checkConcurrentModificationError]);
}
BackendImpact _typeVariableExpression;
BackendImpact get typeVariableExpression {
return _typeVariableExpression ??= new BackendImpact(staticUses: [
helpers.setRuntimeTypeInfo,
helpers.getRuntimeTypeInfo,
helpers.runtimeTypeToString,
helpers.createRuntimeType
], otherImpacts: [
listValues,
getRuntimeTypeArgument,
_needsInt('Needed for accessing a type variable literal on this.')
]);
}
BackendImpact _typeCheck;
BackendImpact get typeCheck {
return _typeCheck ??= new BackendImpact(otherImpacts: [boolValues]);
}
BackendImpact _checkedModeTypeCheck;
BackendImpact get checkedModeTypeCheck {
return _checkedModeTypeCheck ??=
new BackendImpact(staticUses: [helpers.throwRuntimeError]);
}
BackendImpact _malformedTypeCheck;
BackendImpact get malformedTypeCheck {
return _malformedTypeCheck ??= new BackendImpact(
staticUses: compiler.options.useKernel
? [
helpers.malformedTypeError,
]
: [
helpers.throwTypeError,
]);
}
BackendImpact _genericTypeCheck;
BackendImpact get genericTypeCheck {
return _genericTypeCheck ??= new BackendImpact(staticUses: [
helpers.checkSubtype,
// TODO(johnniwinther): Investigate why this is needed.
helpers.setRuntimeTypeInfo,
helpers.getRuntimeTypeInfo
], otherImpacts: [
listValues,
getRuntimeTypeArgument
]);
}
BackendImpact _genericIsCheck;
BackendImpact get genericIsCheck {
return _genericIsCheck ??= new BackendImpact(otherImpacts: [intValues]);
}
BackendImpact _genericCheckedModeTypeCheck;
BackendImpact get genericCheckedModeTypeCheck {
return _genericCheckedModeTypeCheck ??=
new BackendImpact(staticUses: [helpers.assertSubtype]);
}
BackendImpact _typeVariableTypeCheck;
BackendImpact get typeVariableTypeCheck {
return _typeVariableTypeCheck ??=
new BackendImpact(staticUses: [helpers.checkSubtypeOfRuntimeType]);
}
BackendImpact _typeVariableCheckedModeTypeCheck;
BackendImpact get typeVariableCheckedModeTypeCheck {
return _typeVariableCheckedModeTypeCheck ??=
new BackendImpact(staticUses: [helpers.assertSubtypeOfRuntimeType]);
}
BackendImpact _functionTypeCheck;
BackendImpact get functionTypeCheck {
return _functionTypeCheck ??=
new BackendImpact(staticUses: [helpers.functionTypeTestMetaHelper]);
}
BackendImpact _nativeTypeCheck;
BackendImpact get nativeTypeCheck {
return _nativeTypeCheck ??= new BackendImpact(staticUses: [
// We will neeed to add the "$is" and "$as" properties on the
// JavaScript object prototype, so we make sure
// [:defineProperty:] is compiled.
helpers.defineProperty
]);
}
BackendImpact _closure;
BackendImpact get closure {
return _closure ??=
new BackendImpact(instantiatedClasses: [commonElements.functionClass]);
}
BackendImpact _interceptorUse;
BackendImpact get interceptorUse {
return _interceptorUse ??= new BackendImpact(
staticUses: [
helpers.getNativeInterceptorMethod
],
instantiatedClasses: [
helpers.jsJavaScriptObjectClass,
helpers.jsPlainJavaScriptObjectClass,
helpers.jsJavaScriptFunctionClass
],
features: new EnumSet<BackendFeature>.fromValues([
BackendFeature.needToInitializeDispatchProperty,
BackendFeature.needToInitializeIsolateAffinityTag
], fixed: true));
}
BackendImpact _numClasses;
BackendImpact get numClasses {
return _numClasses ??= new BackendImpact(
// The backend will try to optimize number operations and use the
// `iae` helper directly.
globalUses: [helpers.throwIllegalArgumentException]);
}
BackendImpact _listOrStringClasses;
BackendImpact get listOrStringClasses {
return _listOrStringClasses ??= new BackendImpact(
// The backend will try to optimize array and string access and use the
// `ioore` and `iae` helpers directly.
globalUses: [
helpers.throwIndexOutOfRangeException,
helpers.throwIllegalArgumentException
]);
}
BackendImpact _functionClass;
BackendImpact get functionClass {
return _functionClass ??=
new BackendImpact(globalClasses: [helpers.closureClass]);
}
BackendImpact _mapClass;
BackendImpact get mapClass {
return _mapClass ??= new BackendImpact(
// The backend will use a literal list to initialize the entries
// of the map.
globalClasses: [
helpers.coreClasses.listClass,
helpers.mapLiteralClass
]);
}
BackendImpact _boundClosureClass;
BackendImpact get boundClosureClass {
return _boundClosureClass ??=
new BackendImpact(globalClasses: [helpers.boundClosureClass]);
}
BackendImpact _nativeOrExtendsClass;
BackendImpact get nativeOrExtendsClass {
return _nativeOrExtendsClass ??= new BackendImpact(globalUses: [
helpers.getNativeInterceptorMethod
], globalClasses: [
helpers.jsInterceptorClass,
helpers.jsJavaScriptObjectClass,
helpers.jsPlainJavaScriptObjectClass,
helpers.jsJavaScriptFunctionClass
]);
}
BackendImpact _mapLiteralClass;
BackendImpact get mapLiteralClass {
return _mapLiteralClass ??= new BackendImpact(globalUses: [
helpers.mapLiteralConstructor,
helpers.mapLiteralConstructorEmpty,
helpers.mapLiteralUntypedMaker,
helpers.mapLiteralUntypedEmptyMaker
]);
}
BackendImpact _closureClass;
BackendImpact get closureClass {
return _closureClass ??=
new BackendImpact(globalUses: [helpers.closureFromTearOff]);
}
BackendImpact _listClasses;
BackendImpact get listClasses {
return _listClasses ??= new BackendImpact(
// Literal lists can be translated into calls to these functions:
globalUses: [
helpers.jsArrayTypedConstructor,
helpers.setRuntimeTypeInfo,
helpers.getTypeArgumentByIndex
]);
}
BackendImpact _jsIndexingBehavior;
BackendImpact get jsIndexingBehavior {
return _jsIndexingBehavior ??= new BackendImpact(
// These two helpers are used by the emitter and the codegen.
// Because we cannot enqueue elements at the time of emission,
// we make sure they are always generated.
globalUses: [helpers.isJsIndexable]);
}
BackendImpact _enableTypeAssertions;
BackendImpact get enableTypeAssertions {
return _enableTypeAssertions ??= new BackendImpact(
// Register the helper that checks if the expression in an if/while/for
// is a boolean.
// TODO(johnniwinther): Should this be registered through a [Feature]
// instead?
globalUses: [helpers.boolConversionCheck]);
}
BackendImpact _traceHelper;
BackendImpact get traceHelper {
return _traceHelper ??=
new BackendImpact(globalUses: [helpers.traceHelper]);
}
BackendImpact _assertUnreachable;
BackendImpact get assertUnreachable {
return _assertUnreachable ??=
new BackendImpact(globalUses: [helpers.assertUnreachableMethod]);
}
BackendImpact _runtimeTypeSupport;
BackendImpact get runtimeTypeSupport {
return _runtimeTypeSupport ??= new BackendImpact(
globalClasses: [helpers.coreClasses.listClass],
globalUses: [helpers.setRuntimeTypeInfo, helpers.getRuntimeTypeInfo],
otherImpacts: [getRuntimeTypeArgument, computeSignature]);
}
BackendImpact _deferredLoading;
BackendImpact get deferredLoading {
return _deferredLoading ??=
new BackendImpact(globalUses: [helpers.checkDeferredIsLoaded],
// Also register the types of the arguments passed to this method.
globalClasses: [helpers.coreClasses.stringClass]);
}
BackendImpact _noSuchMethodSupport;
BackendImpact get noSuchMethodSupport {
return _noSuchMethodSupport ??= new BackendImpact(
staticUses: [helpers.createInvocationMirror],
dynamicUses: [Selectors.noSuchMethod_]);
}
BackendImpact _isolateSupport;
/// Backend impact for isolate support.
BackendImpact get isolateSupport {
return _isolateSupport ??=
new BackendImpact(globalUses: [helpers.startRootIsolate]);
}
BackendImpact _isolateSupportForResolution;
/// Additional backend impact for isolate support in resolution.
BackendImpact get isolateSupportForResolution {
return _isolateSupportForResolution ??= new BackendImpact(
globalUses: [helpers.currentIsolate, helpers.callInIsolate]);
}
BackendImpact _loadLibrary;
/// Backend impact for accessing a `loadLibrary` function on a deferred
/// prefix.
BackendImpact get loadLibrary {
return _loadLibrary ??=
new BackendImpact(globalUses: [helpers.loadLibraryWrapper]);
}
BackendImpact _memberClosure;
/// Backend impact for performing member closurization.
BackendImpact get memberClosure {
return _memberClosure ??=
new BackendImpact(globalClasses: [helpers.boundClosureClass]);
}
BackendImpact _staticClosure;
/// Backend impact for performing closurization of a top-level or static
/// function.
BackendImpact get staticClosure {
return _staticClosure ??=
new BackendImpact(globalClasses: [helpers.closureClass]);
}
}