| // 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' show |
| Identifiers; |
| import '../compiler.dart' show |
| Compiler; |
| import '../core_types.dart' show |
| CoreClasses; |
| import '../dart_types.dart' show |
| InterfaceType; |
| import '../elements/elements.dart' show |
| ClassElement, |
| Element; |
| |
| import 'backend_helpers.dart'; |
| import 'constant_system_javascript.dart'; |
| import 'js_backend.dart'; |
| |
| /// A set of JavaScript backend dependencies. |
| class BackendImpact { |
| final List<Element> staticUses; |
| final List<InterfaceType> instantiatedTypes; |
| final List<ClassElement> instantiatedClasses; |
| final List<BackendImpact> otherImpacts; |
| |
| BackendImpact({this.staticUses: const <Element>[], |
| this.instantiatedTypes: const <InterfaceType>[], |
| this.instantiatedClasses: const <ClassElement>[], |
| this.otherImpacts: const <BackendImpact>[]}); |
| } |
| |
| /// 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; |
| |
| CoreClasses get coreClasses => compiler.coreClasses; |
| |
| BackendImpact _getRuntimeTypeArgument; |
| |
| BackendImpact get getRuntimeTypeArgument { |
| if (_getRuntimeTypeArgument == null) { |
| _getRuntimeTypeArgument = new BackendImpact( |
| staticUses: [ |
| helpers.getRuntimeTypeArgument, |
| helpers.getTypeArgumentByIndex, |
| helpers.copyTypeArguments]); |
| } |
| return _getRuntimeTypeArgument; |
| } |
| |
| BackendImpact _computeSignature; |
| |
| BackendImpact get computeSignature { |
| if (_computeSignature == null) { |
| _computeSignature = new BackendImpact( |
| staticUses: [ |
| helpers.setRuntimeTypeInfo, |
| helpers.getRuntimeTypeInfo, |
| helpers.computeSignature, |
| helpers.getRuntimeTypeArguments], |
| instantiatedClasses: [ |
| coreClasses.listClass]); |
| } |
| return _computeSignature; |
| } |
| |
| BackendImpact _asyncBody; |
| |
| BackendImpact get asyncBody { |
| if (_asyncBody == null) { |
| _asyncBody = new BackendImpact( |
| staticUses: [ |
| helpers.asyncHelper, |
| helpers.syncCompleterConstructor, |
| helpers.streamIteratorConstructor, |
| helpers.wrapBody]); |
| } |
| return _asyncBody; |
| } |
| |
| BackendImpact _syncStarBody; |
| |
| BackendImpact get syncStarBody { |
| if (_syncStarBody == null) { |
| _syncStarBody = new BackendImpact( |
| staticUses: [ |
| helpers.syncStarIterableConstructor, |
| helpers.endOfIteration, |
| helpers.yieldStar, |
| helpers.syncStarUncaughtError], |
| instantiatedClasses: [ |
| helpers.syncStarIterable]); |
| } |
| return _syncStarBody; |
| } |
| |
| BackendImpact _asyncStarBody; |
| |
| BackendImpact get asyncStarBody { |
| if (_asyncStarBody == null) { |
| _asyncStarBody = new BackendImpact( |
| staticUses: [ |
| helpers.asyncStarHelper, |
| helpers.streamOfController, |
| helpers.yieldSingle, |
| helpers.yieldStar, |
| helpers.asyncStarControllerConstructor, |
| helpers.streamIteratorConstructor, |
| helpers.wrapBody], |
| instantiatedClasses: [ |
| helpers.asyncStarController]); |
| } |
| return _asyncStarBody; |
| } |
| |
| BackendImpact _typeVariableBoundCheck; |
| |
| BackendImpact get typeVariableBoundCheck { |
| if (_typeVariableBoundCheck == null) { |
| _typeVariableBoundCheck = new BackendImpact( |
| staticUses: [ |
| helpers.throwTypeError, |
| helpers.assertIsSubtype]); |
| } |
| return _typeVariableBoundCheck; |
| } |
| |
| BackendImpact _abstractClassInstantiation; |
| |
| BackendImpact get abstractClassInstantiation { |
| if (_abstractClassInstantiation == null) { |
| _abstractClassInstantiation = new BackendImpact( |
| staticUses: [ |
| helpers.throwAbstractClassInstantiationError], |
| otherImpacts: [ |
| _needsString('Needed to encode the message.')]); |
| } |
| return _abstractClassInstantiation; |
| } |
| |
| BackendImpact _fallThroughError; |
| |
| BackendImpact get fallThroughError { |
| if (_fallThroughError == null) { |
| _fallThroughError = new BackendImpact( |
| staticUses: [ |
| helpers.fallThroughError]); |
| } |
| return _fallThroughError; |
| } |
| |
| BackendImpact _asCheck; |
| |
| BackendImpact get asCheck { |
| if (_asCheck == null) { |
| _asCheck = new BackendImpact( |
| staticUses: [ |
| helpers.throwRuntimeError]); |
| } |
| return _asCheck; |
| } |
| |
| BackendImpact _throwNoSuchMethod; |
| |
| BackendImpact get throwNoSuchMethod { |
| if (_throwNoSuchMethod == null) { |
| _throwNoSuchMethod = new BackendImpact( |
| staticUses: [ |
| 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.')]); |
| } |
| return _throwNoSuchMethod; |
| } |
| |
| BackendImpact _throwRuntimeError; |
| |
| BackendImpact get throwRuntimeError { |
| if (_throwRuntimeError == null) { |
| _throwRuntimeError = new BackendImpact( |
| staticUses: [ |
| helpers.throwRuntimeError], |
| // Also register the types of the arguments passed to this method. |
| instantiatedClasses: [ |
| coreClasses.stringClass]); |
| } |
| return _throwRuntimeError; |
| } |
| |
| BackendImpact _superNoSuchMethod; |
| |
| BackendImpact get superNoSuchMethod { |
| if (_superNoSuchMethod == null) { |
| _superNoSuchMethod = new BackendImpact( |
| staticUses: [ |
| helpers.createInvocationMirror, |
| coreClasses.objectClass.lookupLocalMember( |
| Identifiers.noSuchMethod_)], |
| 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.')]); |
| } |
| return _superNoSuchMethod; |
| } |
| |
| 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 { |
| if (_symbolConstructor == null) { |
| _symbolConstructor = new BackendImpact( |
| staticUses: [ |
| helpers.compiler.symbolValidatedConstructor]); |
| } |
| return _symbolConstructor; |
| } |
| |
| BackendImpact _constSymbol; |
| |
| BackendImpact get constSymbol { |
| if (_constSymbol == null) { |
| _constSymbol = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.symbolClass], |
| staticUses: [ |
| compiler.symbolConstructor.declaration]); |
| } |
| return _constSymbol; |
| } |
| |
| BackendImpact _incDecOperation; |
| |
| BackendImpact get incDecOperation { |
| if (_incDecOperation == null) { |
| _incDecOperation = |
| _needsInt('Needed for the `+ 1` or `- 1` operation of ++/--.'); |
| } |
| return _incDecOperation; |
| } |
| |
| /// Helper for registering that `int` is needed. |
| BackendImpact _needsInt(String reason) { |
| // TODO(johnniwinther): Register [reason] for use in dump-info. |
| return new BackendImpact( |
| instantiatedClasses: [coreClasses.intClass]); |
| } |
| |
| /// Helper for registering that `List` is needed. |
| BackendImpact _needsList(String reason) { |
| // TODO(johnniwinther): Register [reason] for use in dump-info. |
| return new BackendImpact( |
| instantiatedClasses: [coreClasses.listClass]); |
| } |
| |
| /// Helper for registering that `String` is needed. |
| BackendImpact _needsString(String reason) { |
| // TODO(johnniwinther): Register [reason] for use in dump-info. |
| return new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.stringClass]); |
| } |
| |
| BackendImpact _assertWithoutMessage; |
| |
| BackendImpact get assertWithoutMessage { |
| if (_assertWithoutMessage == null) { |
| _assertWithoutMessage = new BackendImpact( |
| staticUses: [ |
| helpers.assertHelper]); |
| } |
| return _assertWithoutMessage; |
| } |
| |
| BackendImpact _assertWithMessage; |
| |
| BackendImpact get assertWithMessage { |
| if (_assertWithMessage == null) { |
| _assertWithMessage = new BackendImpact( |
| staticUses: [ |
| helpers.assertTest, |
| helpers.assertThrow]); |
| } |
| return _assertWithMessage; |
| } |
| |
| BackendImpact _asyncForIn; |
| |
| BackendImpact get asyncForIn { |
| if (_asyncForIn == null) { |
| _asyncForIn = new BackendImpact( |
| staticUses: [ |
| helpers.streamIteratorConstructor]); |
| } |
| return _asyncForIn; |
| } |
| |
| BackendImpact _stringInterpolation; |
| |
| BackendImpact get stringInterpolation { |
| if (_stringInterpolation == null) { |
| _stringInterpolation = new BackendImpact( |
| staticUses: [ |
| helpers.stringInterpolationHelper], |
| otherImpacts: [ |
| _needsString('Strings are created.')]); |
| } |
| return _stringInterpolation; |
| } |
| |
| BackendImpact _stringJuxtaposition; |
| |
| BackendImpact get stringJuxtaposition { |
| if (_stringJuxtaposition == null) { |
| _stringJuxtaposition = _needsString('String.concat is used.'); |
| } |
| return _stringJuxtaposition; |
| } |
| |
| // TODO(johnniwinther): Point to to the JavaScript classes instead of the Dart |
| // classes in these impacts. |
| BackendImpact _nullLiteral; |
| |
| BackendImpact get nullLiteral { |
| if (_nullLiteral == null) { |
| _nullLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.nullClass]); |
| } |
| return _nullLiteral; |
| } |
| |
| BackendImpact _boolLiteral; |
| |
| BackendImpact get boolLiteral { |
| if (_boolLiteral == null) { |
| _boolLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.boolClass]); |
| } |
| return _boolLiteral; |
| } |
| |
| BackendImpact _intLiteral; |
| |
| BackendImpact get intLiteral { |
| if (_intLiteral == null) { |
| _intLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.intClass]); |
| } |
| return _intLiteral; |
| } |
| |
| BackendImpact _doubleLiteral; |
| |
| BackendImpact get doubleLiteral { |
| if (_doubleLiteral == null) { |
| _doubleLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.doubleClass]); |
| } |
| return _doubleLiteral; |
| } |
| |
| BackendImpact _stringLiteral; |
| |
| BackendImpact get stringLiteral { |
| if (_stringLiteral == null) { |
| _stringLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.stringClass]); |
| } |
| return _stringLiteral; |
| } |
| |
| BackendImpact _catchStatement; |
| |
| BackendImpact get catchStatement { |
| if (_catchStatement == null) { |
| _catchStatement = new BackendImpact( |
| staticUses: [ |
| helpers.exceptionUnwrapper], |
| instantiatedClasses: [ |
| helpers.jsPlainJavaScriptObjectClass, |
| helpers.jsUnknownJavaScriptObjectClass]); |
| } |
| return _catchStatement; |
| } |
| |
| BackendImpact _throwExpression; |
| |
| BackendImpact get throwExpression { |
| if (_throwExpression == null) { |
| _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]); |
| } |
| return _throwExpression; |
| } |
| |
| BackendImpact _lazyField; |
| |
| BackendImpact get lazyField { |
| if (_lazyField == null) { |
| _lazyField = new BackendImpact( |
| staticUses: [ |
| helpers.cyclicThrowHelper]); |
| } |
| return _lazyField; |
| } |
| |
| BackendImpact _typeLiteral; |
| |
| BackendImpact get typeLiteral { |
| if (_typeLiteral == null) { |
| _typeLiteral = new BackendImpact( |
| instantiatedClasses: [ |
| backend.typeImplementation], |
| staticUses: [ |
| helpers.createRuntimeType]); |
| } |
| return _typeLiteral; |
| } |
| |
| BackendImpact _stackTraceInCatch; |
| |
| BackendImpact get stackTraceInCatch { |
| if (_stackTraceInCatch == null) { |
| _stackTraceInCatch = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.stackTraceClass], |
| staticUses: [ |
| helpers.traceFromException]); |
| } |
| return _stackTraceInCatch; |
| } |
| |
| BackendImpact _syncForIn; |
| |
| BackendImpact get syncForIn { |
| if (_syncForIn == null) { |
| _syncForIn = new BackendImpact( |
| // The SSA builder recognizes certain for-in loops and can generate |
| // calls to throwConcurrentModificationError. |
| staticUses: [ |
| helpers.checkConcurrentModificationError]); |
| } |
| return _syncForIn; |
| } |
| |
| BackendImpact _typeVariableExpression; |
| |
| BackendImpact get typeVariableExpression { |
| if (_typeVariableExpression == null) { |
| _typeVariableExpression = new BackendImpact( |
| staticUses: [ |
| helpers.setRuntimeTypeInfo, |
| helpers.getRuntimeTypeInfo, |
| helpers.runtimeTypeToString, |
| helpers.createRuntimeType], |
| instantiatedClasses: [ |
| coreClasses.listClass], |
| otherImpacts: [ |
| getRuntimeTypeArgument, |
| _needsInt('Needed for accessing a type variable literal on this.') |
| ]); |
| } |
| return _typeVariableExpression; |
| } |
| |
| BackendImpact _typeCheck; |
| |
| BackendImpact get typeCheck { |
| if (_typeCheck == null) { |
| _typeCheck = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.boolClass]); |
| } |
| return _typeCheck; |
| } |
| |
| BackendImpact _checkedModeTypeCheck; |
| |
| BackendImpact get checkedModeTypeCheck { |
| if (_checkedModeTypeCheck == null) { |
| _checkedModeTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.throwRuntimeError]); |
| } |
| return _checkedModeTypeCheck; |
| } |
| |
| BackendImpact _malformedTypeCheck; |
| |
| BackendImpact get malformedTypeCheck { |
| if (_malformedTypeCheck == null) { |
| _malformedTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.throwTypeError]); |
| } |
| return _malformedTypeCheck; |
| } |
| |
| BackendImpact _genericTypeCheck; |
| |
| BackendImpact get genericTypeCheck { |
| if (_genericTypeCheck == null) { |
| _genericTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.checkSubtype, |
| // TODO(johnniwinther): Investigate why this is needed. |
| helpers.setRuntimeTypeInfo, |
| helpers.getRuntimeTypeInfo], |
| instantiatedClasses: [ |
| coreClasses.listClass], |
| otherImpacts: [ |
| getRuntimeTypeArgument]); |
| } |
| return _genericTypeCheck; |
| } |
| |
| BackendImpact _genericIsCheck; |
| |
| BackendImpact get genericIsCheck { |
| if (_genericIsCheck == null) { |
| _genericIsCheck = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.listClass]); |
| } |
| return _genericIsCheck; |
| } |
| |
| BackendImpact _genericCheckedModeTypeCheck; |
| |
| BackendImpact get genericCheckedModeTypeCheck { |
| if (_genericCheckedModeTypeCheck == null) { |
| _genericCheckedModeTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.assertSubtype]); |
| } |
| return _genericCheckedModeTypeCheck; |
| } |
| |
| BackendImpact _typeVariableTypeCheck; |
| |
| BackendImpact get typeVariableTypeCheck { |
| if (_typeVariableTypeCheck == null) { |
| _typeVariableTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.checkSubtypeOfRuntimeType]); |
| } |
| return _typeVariableTypeCheck; |
| } |
| |
| BackendImpact _typeVariableCheckedModeTypeCheck; |
| |
| BackendImpact get typeVariableCheckedModeTypeCheck { |
| if (_typeVariableCheckedModeTypeCheck == null) { |
| _typeVariableCheckedModeTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.assertSubtypeOfRuntimeType]); |
| } |
| return _typeVariableCheckedModeTypeCheck; |
| } |
| |
| BackendImpact _functionTypeCheck; |
| |
| BackendImpact get functionTypeCheck { |
| if (_functionTypeCheck == null) { |
| _functionTypeCheck = new BackendImpact( |
| staticUses: [ |
| helpers.functionTypeTestMetaHelper]); |
| } |
| return _functionTypeCheck; |
| } |
| |
| BackendImpact _nativeTypeCheck; |
| |
| BackendImpact get nativeTypeCheck { |
| if (_nativeTypeCheck == null) { |
| _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]); |
| } |
| return _nativeTypeCheck; |
| } |
| |
| BackendImpact _closure; |
| |
| BackendImpact get closure { |
| if (_closure == null) { |
| _closure = new BackendImpact( |
| instantiatedClasses: [ |
| coreClasses.functionClass]); |
| } |
| return _closure; |
| } |
| } |