mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 21:33:03 +00:00
Delete NativeDataResolver
Change-Id: I91d2e1cb8d03bb1d0da7e175c810fa3cf3216962 Reviewed-on: https://dart-review.googlesource.com/54901 Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
parent
a86621318d
commit
351b90cb59
|
@ -5,31 +5,8 @@
|
|||
library dart2js.backend_api;
|
||||
|
||||
import '../common/resolution.dart' show ResolutionImpact;
|
||||
import '../constants/expressions.dart' show ConstantExpression;
|
||||
import '../elements/resolution_types.dart'
|
||||
show ResolutionDartType, ResolutionInterfaceType;
|
||||
import '../tree/tree.dart' show Node;
|
||||
import '../universe/world_impact.dart' show WorldImpact;
|
||||
|
||||
/// Interface for resolving native data for a target specific element.
|
||||
abstract class NativeRegistry {
|
||||
/// Registers [nativeData] as part of the resolution impact.
|
||||
void registerNativeData(dynamic nativeData);
|
||||
}
|
||||
|
||||
/// Interface for resolving calls to foreign functions.
|
||||
abstract class ForeignResolver {
|
||||
/// Returns the constant expression of [node], or `null` if [node] is not
|
||||
/// a constant expression.
|
||||
ConstantExpression getConstant(Node node);
|
||||
|
||||
/// Registers [type] as instantiated.
|
||||
void registerInstantiatedType(ResolutionInterfaceType type);
|
||||
|
||||
/// Resolves [typeName] to a type in the context of [node].
|
||||
ResolutionDartType resolveTypeFromString(Node node, String typeName);
|
||||
}
|
||||
|
||||
/// Target-specific transformation for resolution world impacts.
|
||||
///
|
||||
/// This processes target-agnostic [ResolutionImpact]s and creates [WorldImpact]
|
||||
|
|
|
@ -31,11 +31,9 @@ import '../mirrors_used.dart';
|
|||
import '../options.dart' show CompilerOptions;
|
||||
import '../parser/parser_task.dart';
|
||||
import '../resolution/resolution.dart';
|
||||
import '../tree/tree.dart' show Send, TypeAnnotation;
|
||||
import '../universe/call_structure.dart' show CallStructure;
|
||||
import '../tree/tree.dart' show TypeAnnotation;
|
||||
import '../universe/world_impact.dart' show WorldImpact;
|
||||
import '../universe/feature.dart';
|
||||
import 'backend_api.dart';
|
||||
import 'work.dart' show WorkItem;
|
||||
|
||||
/// [WorkItem] used exclusively by the [ResolutionEnqueuer].
|
||||
|
@ -81,22 +79,6 @@ abstract class Target {
|
|||
/// classes or members being eagerly resolved.
|
||||
bool isTargetSpecificLibrary(LibraryElement element);
|
||||
|
||||
/// Resolve target specific information for [element] and register it with
|
||||
/// [registry].
|
||||
void resolveNativeMember(MemberElement element, NativeRegistry registry) {}
|
||||
|
||||
/// Processes [element] for resolution and returns the [MethodElement] that
|
||||
/// defines the implementation of [element].
|
||||
MethodElement resolveExternalFunction(MethodElement element) => element;
|
||||
|
||||
/// Called when resolving a call to a foreign function. If a non-null value
|
||||
/// is returned, this is stored as native data for [node] in the resolved
|
||||
/// AST.
|
||||
dynamic resolveForeignCall(Send node, Element element,
|
||||
CallStructure callStructure, ForeignResolver resolver) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns `true` if [element] is a default implementation of `noSuchMethod`
|
||||
/// used by the target.
|
||||
bool isDefaultNoSuchMethod(MethodElement element);
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
library js_backend.backend;
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/backend_api.dart'
|
||||
show ForeignResolver, NativeRegistry, ImpactTransformer;
|
||||
import '../common/backend_api.dart' show ImpactTransformer;
|
||||
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
|
||||
import '../common/names.dart' show Uris;
|
||||
import '../common/resolution.dart' show Resolution, Target;
|
||||
|
@ -14,14 +13,11 @@ import '../common/tasks.dart' show CompilerTask;
|
|||
import '../common_elements.dart' show CommonElements, ElementEnvironment;
|
||||
import '../compiler.dart' show Compiler;
|
||||
import '../constants/constant_system.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../constants/values.dart';
|
||||
import '../deferred_load.dart' show DeferredLoadTask, OutputUnitData;
|
||||
import '../dump_info.dart' show DumpInfoTask;
|
||||
import '../elements/elements.dart';
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/names.dart';
|
||||
import '../elements/resolution_types.dart';
|
||||
import '../elements/types.dart';
|
||||
import '../enqueue.dart'
|
||||
show
|
||||
|
@ -41,10 +37,8 @@ import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
|
|||
import '../js_emitter/sorter.dart' show Sorter;
|
||||
import '../library_loader.dart' show LoadedLibraries;
|
||||
import '../native/native.dart' as native;
|
||||
import '../native/resolver.dart';
|
||||
import '../ssa/ssa.dart' show SsaFunctionCompiler;
|
||||
import '../tracer.dart';
|
||||
import '../tree/tree.dart';
|
||||
import '../types/types.dart';
|
||||
import '../universe/call_structure.dart' show CallStructure;
|
||||
import '../universe/class_hierarchy_builder.dart'
|
||||
|
@ -412,7 +406,6 @@ class JavaScriptBackend {
|
|||
|
||||
NativeDataBuilderImpl _nativeDataBuilder;
|
||||
NativeDataBuilder get nativeDataBuilder => _nativeDataBuilder;
|
||||
final NativeDataResolver _nativeDataResolver;
|
||||
OneShotInterceptorData _oneShotInterceptorData;
|
||||
BackendUsageBuilder _backendUsageBuilder;
|
||||
MirrorsDataImpl _mirrorsData;
|
||||
|
@ -436,8 +429,7 @@ class JavaScriptBackend {
|
|||
bool useNewSourceInfo: false})
|
||||
: this.sourceInformationStrategy =
|
||||
compiler.backendStrategy.sourceInformationStrategy,
|
||||
constantCompilerTask = new JavaScriptConstantTask(compiler),
|
||||
_nativeDataResolver = new NativeDataResolverImpl(compiler) {
|
||||
constantCompilerTask = new JavaScriptConstantTask(compiler) {
|
||||
CommonElements commonElements = compiler.frontendStrategy.commonElements;
|
||||
_target = new JavaScriptBackendTarget(this);
|
||||
_mirrorsData = compiler.frontendStrategy.createMirrorsDataBuilder();
|
||||
|
@ -562,23 +554,6 @@ class JavaScriptBackend {
|
|||
return constantCompilerTask.jsConstantCompiler;
|
||||
}
|
||||
|
||||
MethodElement resolveExternalFunction(MethodElement element) {
|
||||
if (isForeign(compiler.frontendStrategy.commonElements, element)) {
|
||||
return element;
|
||||
}
|
||||
if (_nativeDataResolver.isJsInteropMember(element)) {
|
||||
if (element.memberName == const PublicName('[]') ||
|
||||
element.memberName == const PublicName('[]=')) {
|
||||
reporter.reportErrorMessage(
|
||||
element, MessageKind.JS_INTEROP_INDEX_NOT_SUPPORTED);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
return patchResolverTask.measure(() {
|
||||
return patchResolverTask.resolveExternalFunction(element);
|
||||
});
|
||||
}
|
||||
|
||||
bool isForeign(CommonElements commonElements, Element element) =>
|
||||
element.library == commonElements.foreignLibrary;
|
||||
|
||||
|
@ -652,38 +627,6 @@ class JavaScriptBackend {
|
|||
_outputUnitData = compiler.backendStrategy.convertOutputUnitData(data);
|
||||
}
|
||||
|
||||
/// Called when resolving a call to a foreign function.
|
||||
native.NativeBehavior resolveForeignCall(Send node, Element element,
|
||||
CallStructure callStructure, ForeignResolver resolver) {
|
||||
if (element.name == JS) {
|
||||
return _nativeDataResolver.resolveJsCall(node, resolver);
|
||||
} else if (element.name == JS_EMBEDDED_GLOBAL) {
|
||||
return _nativeDataResolver.resolveJsEmbeddedGlobalCall(node, resolver);
|
||||
} else if (element.name == JS_BUILTIN) {
|
||||
return _nativeDataResolver.resolveJsBuiltinCall(node, resolver);
|
||||
} else if (element.name == JS_INTERCEPTOR_CONSTANT) {
|
||||
// The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
|
||||
// a class that will be instantiated outside the program by attaching a
|
||||
// native class dispatch record referencing the interceptor.
|
||||
if (!node.argumentsNode.isEmpty) {
|
||||
Node argument = node.argumentsNode.nodes.head;
|
||||
ConstantExpression constant = resolver.getConstant(argument);
|
||||
if (constant != null && constant.kind == ConstantExpressionKind.TYPE) {
|
||||
TypeConstantExpression typeConstant = constant;
|
||||
if (typeConstant.type is ResolutionInterfaceType) {
|
||||
resolver.registerInstantiatedType(typeConstant.type);
|
||||
// No native behavior for this call.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
reporter.reportErrorMessage(
|
||||
node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
|
||||
}
|
||||
// No native behavior for this call.
|
||||
return null;
|
||||
}
|
||||
|
||||
ResolutionEnqueuer createResolutionEnqueuer(
|
||||
CompilerTask task, Compiler compiler) {
|
||||
ElementEnvironment elementEnvironment =
|
||||
|
@ -1344,22 +1287,6 @@ class JavaScriptBackendTarget extends Target {
|
|||
return _backend.isTargetSpecificLibrary(element);
|
||||
}
|
||||
|
||||
@override
|
||||
void resolveNativeMember(MemberElement element, NativeRegistry registry) {
|
||||
return _backend._nativeDataResolver.resolveNativeMember(element, registry);
|
||||
}
|
||||
|
||||
@override
|
||||
MethodElement resolveExternalFunction(MethodElement element) {
|
||||
return _backend.resolveExternalFunction(element);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic resolveForeignCall(Send node, Element element,
|
||||
CallStructure callStructure, ForeignResolver resolver) {
|
||||
return _backend.resolveForeignCall(node, element, callStructure, resolver);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isDefaultNoSuchMethod(MethodElement element) {
|
||||
return _commonElements.isDefaultNoSuchMethodImplementation(element);
|
||||
|
|
|
@ -3,18 +3,13 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/backend_api.dart' show ForeignResolver;
|
||||
import '../common/resolution.dart' show ParsingContext;
|
||||
import '../constants/values.dart';
|
||||
import '../common_elements.dart' show CommonElements, ElementEnvironment;
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/resolution_types.dart';
|
||||
import '../elements/types.dart';
|
||||
import '../js/js.dart' as js;
|
||||
import '../js_backend/native_data.dart' show NativeBasicData;
|
||||
import '../tree/tree.dart';
|
||||
import '../universe/side_effects.dart' show SideEffects;
|
||||
import '../util/util.dart';
|
||||
import 'js.dart';
|
||||
|
||||
typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString,
|
||||
|
@ -492,61 +487,6 @@ class NativeBehavior {
|
|||
return sideEffects;
|
||||
}
|
||||
|
||||
/// Returns a [TypeLookup] that uses [resolver] to perform lookup and [node]
|
||||
/// as position for errors.
|
||||
static TypeLookup _typeLookup(
|
||||
Node node, DiagnosticReporter reporter, ForeignResolver resolver) {
|
||||
ResolutionDartType lookup(String name, {bool required}) {
|
||||
ResolutionDartType type = resolver.resolveTypeFromString(node, name);
|
||||
if (type == null && required) {
|
||||
reporter.reportErrorMessage(
|
||||
node, MessageKind.GENERIC, {'text': "Type '$name' not found."});
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
/// Compute the [NativeBehavior] for a [Send] node calling the 'JS' function.
|
||||
static NativeBehavior ofJsCallSend(
|
||||
Send jsCall,
|
||||
DiagnosticReporter reporter,
|
||||
ParsingContext parsing,
|
||||
CommonElements commonElements,
|
||||
ForeignResolver resolver) {
|
||||
var argNodes = jsCall.arguments;
|
||||
if (argNodes.isEmpty || argNodes.tail.isEmpty) {
|
||||
reporter.reportErrorMessage(jsCall, MessageKind.WRONG_ARGUMENT_FOR_JS);
|
||||
return new NativeBehavior();
|
||||
}
|
||||
|
||||
dynamic specArgument = argNodes.head;
|
||||
if (specArgument is! StringNode || specArgument.isInterpolation) {
|
||||
reporter.reportErrorMessage(
|
||||
specArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
|
||||
return new NativeBehavior();
|
||||
}
|
||||
|
||||
dynamic codeArgument = argNodes.tail.head;
|
||||
if (codeArgument is! StringNode || codeArgument.isInterpolation) {
|
||||
reporter.reportErrorMessage(
|
||||
codeArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
|
||||
return new NativeBehavior();
|
||||
}
|
||||
|
||||
String specString = specArgument.dartString.slowToString();
|
||||
String codeString = codeArgument.dartString.slowToString();
|
||||
|
||||
return ofJsCall(
|
||||
specString,
|
||||
codeString,
|
||||
_typeLookup(specArgument, reporter, resolver),
|
||||
specArgument,
|
||||
reporter,
|
||||
commonElements);
|
||||
}
|
||||
|
||||
/// Compute the [NativeBehavior] for a call to the 'JS' function with the
|
||||
/// given [specString] and [codeString] (first and second arguments).
|
||||
static NativeBehavior ofJsCall(
|
||||
|
@ -633,50 +573,6 @@ class NativeBehavior {
|
|||
nullType: commonElements.nullType);
|
||||
}
|
||||
|
||||
static NativeBehavior ofJsBuiltinCallSend(
|
||||
Send jsBuiltinCall,
|
||||
DiagnosticReporter reporter,
|
||||
CommonElements commonElements,
|
||||
ForeignResolver resolver) {
|
||||
NativeBehavior behavior = new NativeBehavior();
|
||||
behavior.sideEffects.setTo(new SideEffects());
|
||||
|
||||
// The first argument of a JS-embedded global call is a string encoding
|
||||
// the type of the code.
|
||||
//
|
||||
// 'Type1|Type2'. A union type.
|
||||
// '=Object'. A JavaScript Object, no subtype.
|
||||
|
||||
Link<Node> argNodes = jsBuiltinCall.arguments;
|
||||
if (argNodes.isEmpty) {
|
||||
reporter.internalError(
|
||||
jsBuiltinCall, "JS builtin expression has no type.");
|
||||
}
|
||||
|
||||
// We don't check the given name. That needs to be done at a later point.
|
||||
// This is, because we want to allow non-literals (like references to
|
||||
// enums) as names.
|
||||
if (argNodes.tail.isEmpty) {
|
||||
reporter.internalError(jsBuiltinCall, "JS builtin is missing name.");
|
||||
}
|
||||
|
||||
LiteralString specLiteral = argNodes.head.asLiteralString();
|
||||
if (specLiteral == null) {
|
||||
// TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
|
||||
// is not very satisfactory because it does not work for void, dynamic.
|
||||
reporter.internalError(argNodes.head, "Unexpected first argument.");
|
||||
}
|
||||
|
||||
String specString = specLiteral.dartString.slowToString();
|
||||
|
||||
return ofJsBuiltinCall(
|
||||
specString,
|
||||
_typeLookup(jsBuiltinCall, reporter, resolver),
|
||||
jsBuiltinCall,
|
||||
reporter,
|
||||
commonElements);
|
||||
}
|
||||
|
||||
static NativeBehavior ofJsBuiltinCall(
|
||||
String specString,
|
||||
TypeLookup lookupType,
|
||||
|
@ -690,60 +586,6 @@ class NativeBehavior {
|
|||
return behavior;
|
||||
}
|
||||
|
||||
static NativeBehavior ofJsEmbeddedGlobalCallSend(
|
||||
Send jsEmbeddedGlobalCall,
|
||||
DiagnosticReporter reporter,
|
||||
CommonElements commonElements,
|
||||
ForeignResolver resolver) {
|
||||
NativeBehavior behavior = new NativeBehavior();
|
||||
// TODO(sra): Allow the use site to override these defaults.
|
||||
// Embedded globals are usually pre-computed data structures or JavaScript
|
||||
// functions that never change.
|
||||
behavior.sideEffects.setTo(new SideEffects.empty());
|
||||
behavior.throwBehavior = NativeThrowBehavior.NEVER;
|
||||
|
||||
// The first argument of a JS-embedded global call is a string encoding
|
||||
// the type of the code.
|
||||
//
|
||||
// 'Type1|Type2'. A union type.
|
||||
// '=Object'. A JavaScript Object, no subtype.
|
||||
|
||||
Link<Node> argNodes = jsEmbeddedGlobalCall.arguments;
|
||||
if (argNodes.isEmpty) {
|
||||
reporter.internalError(
|
||||
jsEmbeddedGlobalCall, "JS embedded global expression has no type.");
|
||||
}
|
||||
|
||||
// We don't check the given name. That needs to be done at a later point.
|
||||
// This is, because we want to allow non-literals (like references to
|
||||
// enums) as names.
|
||||
if (argNodes.tail.isEmpty) {
|
||||
reporter.internalError(
|
||||
jsEmbeddedGlobalCall, "JS embedded global is missing name.");
|
||||
}
|
||||
|
||||
if (!argNodes.tail.tail.isEmpty) {
|
||||
reporter.internalError(argNodes.tail.tail.head,
|
||||
'JS embedded global has more than 2 arguments');
|
||||
}
|
||||
|
||||
LiteralString specLiteral = argNodes.head.asLiteralString();
|
||||
if (specLiteral == null) {
|
||||
// TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
|
||||
// is not very satisfactory because it does not work for void, dynamic.
|
||||
reporter.internalError(argNodes.head, "Unexpected first argument.");
|
||||
}
|
||||
|
||||
String specString = specLiteral.dartString.slowToString();
|
||||
|
||||
return ofJsEmbeddedGlobalCall(
|
||||
specString,
|
||||
_typeLookup(jsEmbeddedGlobalCall, reporter, resolver),
|
||||
jsEmbeddedGlobalCall,
|
||||
reporter,
|
||||
commonElements);
|
||||
}
|
||||
|
||||
static NativeBehavior ofJsEmbeddedGlobalCall(
|
||||
String specString,
|
||||
TypeLookup lookupType,
|
||||
|
@ -766,7 +608,7 @@ class NativeBehavior {
|
|||
String typeString, TypeLookup lookupType) {
|
||||
if (typeString == '=Object') return SpecialType.JsObject;
|
||||
if (typeString == 'dynamic') {
|
||||
return const ResolutionDynamicType();
|
||||
return const DynamicType();
|
||||
}
|
||||
int index = typeString.indexOf('<');
|
||||
var type = lookupType(typeString, required: index == -1);
|
||||
|
@ -779,7 +621,7 @@ class NativeBehavior {
|
|||
return type;
|
||||
}
|
||||
}
|
||||
return const ResolutionDynamicType();
|
||||
return const DynamicType();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,74 +2,17 @@
|
|||
// 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.
|
||||
|
||||
import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
|
||||
import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
|
||||
import 'package:front_end/src/scanner/token.dart' show BeginToken;
|
||||
|
||||
import '../common.dart';
|
||||
import '../common_elements.dart' show CommonElements, ElementEnvironment;
|
||||
import '../common/backend_api.dart';
|
||||
import '../common/resolution.dart';
|
||||
import '../compiler.dart' show Compiler;
|
||||
import '../constants/values.dart';
|
||||
import '../elements/elements.dart'
|
||||
show
|
||||
ClassElement,
|
||||
Element,
|
||||
FieldElement,
|
||||
MemberElement,
|
||||
MetadataAnnotation,
|
||||
MethodElement;
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX;
|
||||
import '../elements/resolution_types.dart' show ResolutionDartType;
|
||||
import '../js_backend/js_backend.dart';
|
||||
import '../js_backend/native_data.dart';
|
||||
import '../patch_parser.dart';
|
||||
import '../tree/tree.dart';
|
||||
import 'behavior.dart';
|
||||
|
||||
/// Interface for computing native members.
|
||||
abstract class NativeMemberResolver {
|
||||
/// Computes whether [element] is native or JsInterop and, if so, registers
|
||||
/// its [NativeBehavior]s to [registry].
|
||||
void resolveNativeMember(MemberEntity element, [NativeRegistry registry]);
|
||||
}
|
||||
|
||||
/// Interface for computing native members and [NativeBehavior]s in member code
|
||||
/// based on the AST.
|
||||
abstract class NativeDataResolver implements NativeMemberResolver {
|
||||
/// Returns `true` if [element] is a JsInterop member.
|
||||
bool isJsInteropMember(MemberElement element);
|
||||
|
||||
/// Computes the [NativeBehavior] for a `JS` call, which can be an
|
||||
/// instantiation point for types.
|
||||
///
|
||||
/// For example, the following code instantiates and returns native classes
|
||||
/// that are `_DOMWindowImpl` or a subtype.
|
||||
///
|
||||
/// JS('_DOMWindowImpl', 'window')
|
||||
///
|
||||
NativeBehavior resolveJsCall(Send node, ForeignResolver resolver);
|
||||
|
||||
/// Computes the [NativeBehavior] for a `JS_EMBEDDED_GLOBAL` call, which can
|
||||
/// be an instantiation point for types.
|
||||
///
|
||||
/// For example, the following code instantiates and returns a String class
|
||||
///
|
||||
/// JS_EMBEDDED_GLOBAL('String', 'foo')
|
||||
///
|
||||
NativeBehavior resolveJsEmbeddedGlobalCall(
|
||||
Send node, ForeignResolver resolver);
|
||||
|
||||
/// Computes the [NativeBehavior] for a `JS_BUILTIN` call, which can be an
|
||||
/// instantiation point for types.
|
||||
///
|
||||
/// For example, the following code instantiates and returns a String class
|
||||
///
|
||||
/// JS_BUILTIN('String', 'int2string', 0)
|
||||
///
|
||||
NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver);
|
||||
/// Computes whether [element] is native or JsInterop.
|
||||
void resolveNativeMember(MemberEntity element);
|
||||
}
|
||||
|
||||
abstract class NativeMemberResolverBase implements NativeMemberResolver {
|
||||
|
@ -90,7 +33,7 @@ abstract class NativeMemberResolverBase implements NativeMemberResolver {
|
|||
NativeBehavior computeNativeFieldStoreBehavior(covariant FieldEntity field);
|
||||
|
||||
@override
|
||||
void resolveNativeMember(MemberEntity element, [NativeRegistry registry]) {
|
||||
void resolveNativeMember(MemberEntity element) {
|
||||
bool isJsInterop = isJsInteropMember(element);
|
||||
if (element.isFunction ||
|
||||
element.isConstructor ||
|
||||
|
@ -102,7 +45,6 @@ abstract class NativeMemberResolverBase implements NativeMemberResolver {
|
|||
NativeBehavior behavior =
|
||||
computeNativeMethodBehavior(method, isJsInterop: isJsInterop);
|
||||
nativeDataBuilder.setNativeMethodBehavior(method, behavior);
|
||||
registry?.registerNativeData(behavior);
|
||||
}
|
||||
} else if (element.isField) {
|
||||
FieldEntity field = element;
|
||||
|
@ -115,13 +57,6 @@ abstract class NativeMemberResolverBase implements NativeMemberResolver {
|
|||
nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior);
|
||||
nativeDataBuilder.setNativeFieldStoreBehavior(
|
||||
field, fieldStoreBehavior);
|
||||
|
||||
// TODO(sra): Process fields for storing separately.
|
||||
// We have to handle both loading and storing to the field because we
|
||||
// only get one look at each member and there might be a load or store
|
||||
// we have not seen yet.
|
||||
registry?.registerNativeData(fieldLoadBehavior);
|
||||
registry?.registerNativeData(fieldStoreBehavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,178 +143,6 @@ abstract class NativeMemberResolverBase implements NativeMemberResolver {
|
|||
}
|
||||
}
|
||||
|
||||
class NativeDataResolverImpl extends NativeMemberResolverBase
|
||||
implements NativeDataResolver {
|
||||
final Compiler _compiler;
|
||||
|
||||
NativeDataResolverImpl(this._compiler);
|
||||
|
||||
JavaScriptBackend get _backend => _compiler.backend;
|
||||
DiagnosticReporter get _reporter => _compiler.reporter;
|
||||
ElementEnvironment get elementEnvironment =>
|
||||
_compiler.resolution.elementEnvironment;
|
||||
CommonElements get commonElements => _compiler.resolution.commonElements;
|
||||
NativeBasicData get nativeBasicData =>
|
||||
_compiler.frontendStrategy.nativeBasicData;
|
||||
NativeDataBuilder get nativeDataBuilder => _backend.nativeDataBuilder;
|
||||
|
||||
@override
|
||||
bool isJsInteropMember(MemberElement element) {
|
||||
// TODO(johnniwinther): Avoid computing this twice for external function;
|
||||
// once from JavaScriptBackendTarget.resolveExternalFunction and once
|
||||
// through JavaScriptBackendTarget.resolveNativeMember.
|
||||
bool isJsInterop =
|
||||
checkJsInteropMemberAnnotations(_compiler, element, nativeDataBuilder);
|
||||
// TODO(johnniwinther): Avoid this duplication of logic from
|
||||
// NativeData.isJsInterop.
|
||||
if (!isJsInterop && element is MethodElement && element.isExternal) {
|
||||
if (element.enclosingClass != null) {
|
||||
isJsInterop = nativeBasicData.isJsInteropClass(element.enclosingClass);
|
||||
} else {
|
||||
isJsInterop = nativeBasicData.isJsInteropLibrary(element.library);
|
||||
}
|
||||
}
|
||||
return isJsInterop;
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior computeNativeMethodBehavior(MethodElement function,
|
||||
{bool isJsInterop}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior computeNativeFieldLoadBehavior(FieldElement field,
|
||||
{bool isJsInterop}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior computeNativeFieldStoreBehavior(FieldElement field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isNativeMethod(FunctionElementX element) {
|
||||
if (!_backend.canLibraryUseNative(element.library)) return false;
|
||||
// Native method?
|
||||
return _reporter.withCurrentElement(element, () {
|
||||
Node node = element.parseNode(_compiler.resolution.parsingContext);
|
||||
if (node is! FunctionExpression) return false;
|
||||
FunctionExpression functionExpression = node;
|
||||
node = functionExpression.body;
|
||||
Token token = node.getBeginToken();
|
||||
if (identical(token.stringValue, 'native')) {
|
||||
element.isMarkedNative = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior resolveJsCall(Send node, ForeignResolver resolver) {
|
||||
return NativeBehavior.ofJsCallSend(
|
||||
node, _reporter, _compiler.parsingContext, commonElements, resolver);
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior resolveJsEmbeddedGlobalCall(
|
||||
Send node, ForeignResolver resolver) {
|
||||
return NativeBehavior.ofJsEmbeddedGlobalCallSend(
|
||||
node, _reporter, commonElements, resolver);
|
||||
}
|
||||
|
||||
@override
|
||||
NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver) {
|
||||
return NativeBehavior.ofJsBuiltinCallSend(
|
||||
node, _reporter, commonElements, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
/// Annotation handler for pre-resolution detection of `@Native(...)`
|
||||
/// annotations.
|
||||
class NativeAnnotationHandler extends EagerAnnotationHandler<String> {
|
||||
final NativeBasicDataBuilder _nativeBasicDataBuilder;
|
||||
|
||||
NativeAnnotationHandler(this._nativeBasicDataBuilder);
|
||||
|
||||
String getNativeAnnotation(MetadataAnnotationX annotation) {
|
||||
if (annotation.beginToken != null &&
|
||||
annotation.beginToken.next.lexeme == 'Native') {
|
||||
// Skipping '@', 'Native', and '('.
|
||||
Token argument = annotation.beginToken.next.next.next;
|
||||
if (argument is StringToken) {
|
||||
return argument.lexeme;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String apply(
|
||||
Compiler compiler, Element element, MetadataAnnotation annotation) {
|
||||
if (element.isClass) {
|
||||
ClassElement cls = element;
|
||||
String native = getNativeAnnotation(annotation);
|
||||
if (native != null) {
|
||||
String tagText = native.substring(1, native.length - 1);
|
||||
_nativeBasicDataBuilder.setNativeClassTagInfo(cls, tagText);
|
||||
return native;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void validate(Compiler compiler, Element element,
|
||||
MetadataAnnotation annotation, ConstantValue constant) {
|
||||
ResolutionDartType annotationType =
|
||||
constant.getType(compiler.resolution.commonElements);
|
||||
if (annotationType.element !=
|
||||
compiler.resolution.commonElements.nativeAnnotationClass) {
|
||||
DiagnosticReporter reporter = compiler.reporter;
|
||||
reporter.internalError(annotation, 'Invalid @Native(...) annotation.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool checkJsInteropMemberAnnotations(Compiler compiler, MemberElement element,
|
||||
NativeDataBuilder nativeDataBuilder) {
|
||||
bool isJsInterop = EagerAnnotationHandler.checkAnnotation(
|
||||
compiler, element, const JsInteropAnnotationHandler());
|
||||
if (isJsInterop) {
|
||||
nativeDataBuilder.markAsJsInteropMember(element);
|
||||
}
|
||||
return isJsInterop;
|
||||
}
|
||||
|
||||
/// Annotation handler for pre-resolution detection of `@JS(...)`
|
||||
/// annotations.
|
||||
class JsInteropAnnotationHandler implements EagerAnnotationHandler<bool> {
|
||||
const JsInteropAnnotationHandler();
|
||||
|
||||
bool hasJsNameAnnotation(MetadataAnnotationX annotation) =>
|
||||
annotation.beginToken != null &&
|
||||
annotation.beginToken.next.lexeme == 'JS';
|
||||
|
||||
bool apply(
|
||||
Compiler compiler, Element element, MetadataAnnotation annotation) {
|
||||
return hasJsNameAnnotation(annotation);
|
||||
}
|
||||
|
||||
@override
|
||||
void validate(Compiler compiler, Element element,
|
||||
MetadataAnnotation annotation, ConstantValue constant) {
|
||||
ResolutionDartType type =
|
||||
constant.getType(compiler.resolution.commonElements);
|
||||
if (type.element != compiler.resolution.commonElements.jsAnnotationClass) {
|
||||
compiler.reporter
|
||||
.internalError(annotation, 'Invalid @JS(...) annotation.');
|
||||
}
|
||||
}
|
||||
|
||||
bool get defaultResult => false;
|
||||
}
|
||||
|
||||
/// Determines all native classes in a set of libraries.
|
||||
abstract class NativeClassFinder {
|
||||
/// Returns the set of all native classes declared in [libraries].
|
||||
|
@ -494,98 +257,6 @@ class BaseNativeClassFinder implements NativeClassFinder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Native class finder that extends [BaseNativeClassFinder] to handle
|
||||
/// unresolved classes encountered during the native classes computation.
|
||||
class ResolutionNativeClassFinder extends BaseNativeClassFinder {
|
||||
final DiagnosticReporter _reporter;
|
||||
final Resolution _resolution;
|
||||
|
||||
ResolutionNativeClassFinder(
|
||||
this._resolution,
|
||||
this._reporter,
|
||||
ElementEnvironment elementEnvironment,
|
||||
CommonElements commonElements,
|
||||
NativeBasicData nativeBasicData)
|
||||
: super(elementEnvironment, nativeBasicData);
|
||||
|
||||
void _processNativeClass(
|
||||
ClassElement classElement, Set<ClassEntity> nativeClasses) {
|
||||
// Resolve class to ensure the class has valid inheritance info.
|
||||
classElement.ensureResolved(_resolution);
|
||||
super._processNativeClass(classElement, nativeClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source string of the class named in the extends clause, or
|
||||
* `null` if there is no extends clause.
|
||||
*/
|
||||
String _findExtendsNameOfClass(ClassElement classElement) {
|
||||
if (classElement.isResolved) {
|
||||
ClassElement superClass = classElement.superclass;
|
||||
while (superClass != null) {
|
||||
if (!superClass.isUnnamedMixinApplication) {
|
||||
return superClass.name;
|
||||
}
|
||||
superClass = superClass.superclass;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// "class B extends A ... {}" --> "A"
|
||||
// "class B extends foo.A ... {}" --> "A"
|
||||
// "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A"
|
||||
|
||||
// We want to avoid calling classElement.parseNode on every class. Doing so
|
||||
// will slightly increase parse time and size and cause compiler errors and
|
||||
// warnings to me emitted in more unused code.
|
||||
|
||||
// An alternative to this code is to extend the API of ClassElement to
|
||||
// expose the name of the extended element.
|
||||
|
||||
// Pattern match the above cases in the token stream.
|
||||
// [abstract] class X extends [id.]* id
|
||||
|
||||
Token skipTypeParameters(Token token) {
|
||||
BeginToken beginGroupToken = token;
|
||||
Token endToken = beginGroupToken.endGroup;
|
||||
return endToken.next;
|
||||
//for (;;) {
|
||||
// token = token.next;
|
||||
// if (token.stringValue == '>') return token.next;
|
||||
// if (token.stringValue == '<') return skipTypeParameters(token);
|
||||
//}
|
||||
}
|
||||
|
||||
String scanForExtendsName(Token token) {
|
||||
if (token.stringValue == 'abstract') token = token.next;
|
||||
if (token.stringValue != 'class') return null;
|
||||
token = token.next;
|
||||
if (!token.isIdentifier) return null;
|
||||
token = token.next;
|
||||
// class F<X extends B<X>> extends ...
|
||||
if (token.stringValue == '<') {
|
||||
token = skipTypeParameters(token);
|
||||
}
|
||||
if (token.stringValue != 'extends') return null;
|
||||
token = token.next;
|
||||
Token id = token;
|
||||
while (token.kind != Tokens.EOF_TOKEN) {
|
||||
token = token.next;
|
||||
if (token.stringValue != '.') break;
|
||||
token = token.next;
|
||||
if (!token.isIdentifier) return null;
|
||||
id = token;
|
||||
}
|
||||
// Should be at '{', 'with', 'implements', '<' or 'native'.
|
||||
return id.lexeme;
|
||||
}
|
||||
|
||||
return _reporter.withCurrentElement(classElement, () {
|
||||
return scanForExtendsName(classElement.position);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if [value] is named annotation based on [annotationClass].
|
||||
bool isAnnotation(
|
||||
Spannable spannable, ConstantValue value, ClassEntity annotationClass) {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
library dart2js.resolution.registry;
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/backend_api.dart' show ForeignResolver, NativeRegistry;
|
||||
import '../common/resolution.dart' show ResolutionImpact, Target;
|
||||
import '../constants/expressions.dart';
|
||||
import '../diagnostics/source_span.dart';
|
||||
|
@ -24,7 +23,7 @@ import '../util/util.dart' show Setlet;
|
|||
import 'tree_elements.dart' show TreeElementMapping;
|
||||
|
||||
class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
implements NativeRegistry, ResolutionImpact {
|
||||
implements ResolutionImpact {
|
||||
final String name;
|
||||
EnumSet<Feature> _features;
|
||||
Setlet<MapLiteralUse> _mapLiterals;
|
||||
|
@ -383,15 +382,7 @@ class ResolutionRegistry {
|
|||
}
|
||||
|
||||
void registerForeignCall(
|
||||
Node node, Element element, CallStructure callStructure) {
|
||||
var nativeData = target.resolveForeignCall(
|
||||
node, element, callStructure, new ForeignResolutionResolver(this));
|
||||
if (nativeData != null) {
|
||||
// Split impact from resolution result.
|
||||
mapping.registerNativeData(node, nativeData);
|
||||
impactBuilder.registerNativeData(nativeData);
|
||||
}
|
||||
}
|
||||
Node node, Element element, CallStructure callStructure) {}
|
||||
|
||||
void registerDynamicUse(DynamicUse dynamicUse) {
|
||||
impactBuilder.registerDynamicUse(dynamicUse);
|
||||
|
@ -425,24 +416,3 @@ class ResolutionRegistry {
|
|||
impactBuilder.registerSeenClass(seenClass);
|
||||
}
|
||||
}
|
||||
|
||||
class ForeignResolutionResolver implements ForeignResolver {
|
||||
final ResolutionRegistry registry;
|
||||
|
||||
ForeignResolutionResolver(this.registry);
|
||||
|
||||
@override
|
||||
ConstantExpression getConstant(Node node) {
|
||||
return registry.getConstant(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerInstantiatedType(ResolutionInterfaceType type) {
|
||||
registry.registerInstantiation(type);
|
||||
}
|
||||
|
||||
@override
|
||||
ResolutionDartType resolveTypeFromString(Node node, String typeName) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue