Split js interop registration into library/class/member elements

R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2731163002 .
This commit is contained in:
Johnni Winther
2017-03-15 12:58:55 +01:00
parent bd3cfd6979
commit fbbf1e90ec
12 changed files with 264 additions and 161 deletions
@@ -39,7 +39,9 @@ class JavaScriptBackendSerialization implements BackendSerialization {
deserializer = new JavaScriptBackendDeserializer(nativeData);
}
const Key JS_INTEROP_NAME = const Key('jsInteropName');
const Key JS_INTEROP_LIBRARY_NAME = const Key('jsInteropLibraryName');
const Key JS_INTEROP_CLASS_NAME = const Key('jsInteropClassName');
const Key JS_INTEROP_MEMBER_NAME = const Key('jsInteropMemberName');
const Key NATIVE_MEMBER_NAME = const Key('nativeMemberName');
const Key NATIVE_CLASS_TAG_INFO = const Key('nativeClassTagInfo');
const Key NATIVE_METHOD_BEHAVIOR = const Key('nativeMethodBehavior');
@@ -58,9 +60,17 @@ class JavaScriptBackendSerializer implements SerializerPlugin {
return encoder ??= createEncoder(_BACKEND_DATA_TAG);
}
String jsInteropName = nativeData.jsInteropNames[element];
if (jsInteropName != null) {
getEncoder().setString(JS_INTEROP_NAME, jsInteropName);
String jsInteropLibraryName = nativeData.jsInteropLibraryNames[element];
if (jsInteropLibraryName != null) {
getEncoder().setString(JS_INTEROP_LIBRARY_NAME, jsInteropLibraryName);
}
String jsInteropClassName = nativeData.jsInteropClassNames[element];
if (jsInteropClassName != null) {
getEncoder().setString(JS_INTEROP_CLASS_NAME, jsInteropClassName);
}
String jsInteropMemberName = nativeData.jsInteropMemberNames[element];
if (jsInteropMemberName != null) {
getEncoder().setString(JS_INTEROP_MEMBER_NAME, jsInteropMemberName);
}
String nativeMemberName = nativeData.nativeMemberName[element];
if (nativeMemberName != null) {
@@ -107,10 +117,20 @@ class JavaScriptBackendDeserializer implements DeserializerPlugin {
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
ObjectDecoder decoder = getDecoder(_BACKEND_DATA_TAG);
if (decoder != null) {
String jsInteropName =
decoder.getString(JS_INTEROP_NAME, isOptional: true);
if (jsInteropName != null) {
nativeData.jsInteropNames[element] = jsInteropName;
String jsInteropLibraryName =
decoder.getString(JS_INTEROP_LIBRARY_NAME, isOptional: true);
if (jsInteropLibraryName != null) {
nativeData.jsInteropLibraryNames[element] = jsInteropLibraryName;
}
String jsInteropClassName =
decoder.getString(JS_INTEROP_CLASS_NAME, isOptional: true);
if (jsInteropClassName != null) {
nativeData.jsInteropClassNames[element] = jsInteropClassName;
}
String jsInteropMemberName =
decoder.getString(JS_INTEROP_MEMBER_NAME, isOptional: true);
if (jsInteropMemberName != null) {
nativeData.jsInteropMemberNames[element] = jsInteropMemberName;
}
String nativeMemberName =
decoder.getString(NATIVE_MEMBER_NAME, isOptional: true);
@@ -13,7 +13,7 @@ abstract class _MinifiedFieldNamer implements Namer {
// The inheritance scope based naming might not yield a name. For instance,
// this could be because the field belongs to a mixin. In such a case this
// will return `null` and a normal field name has to be used.
jsAst.Name _minifiedInstanceFieldPropertyName(Element element) {
jsAst.Name _minifiedInstanceFieldPropertyName(FieldElement element) {
if (_nativeData.hasFixedBackendName(element)) {
return new StringBackedName(_nativeData.getFixedBackendName(element));
}
@@ -64,7 +64,7 @@ class FrequencyBasedNamer extends Namer
}
@override
jsAst.Name instanceFieldPropertyName(Element element) {
jsAst.Name instanceFieldPropertyName(FieldElement element) {
jsAst.Name proposed = _minifiedInstanceFieldPropertyName(element);
if (proposed != null) {
return proposed;
@@ -16,9 +16,9 @@ import '../elements/elements.dart'
ClassElement,
Element,
FieldElement,
FunctionElement,
LibraryElement,
ParameterElement,
MemberElement,
MethodElement,
MetadataAnnotation;
import '../js/js.dart' as jsAst;
@@ -57,8 +57,10 @@ class JsInteropAnalysis {
_inCodegen = true;
}
void processJsInteropAnnotation(Element e) {
for (MetadataAnnotation annotation in e.implementation.metadata) {
/// Resolves the metadata of [element] and returns the name of the `JS(...)`
/// annotation for js interop, if found.
String processJsInteropAnnotation(Element element) {
for (MetadataAnnotation annotation in element.implementation.metadata) {
// TODO(johnniwinther): Avoid processing unresolved elements.
if (annotation.constant == null) continue;
ConstantValue constant =
@@ -67,18 +69,19 @@ class JsInteropAnalysis {
ConstructedConstantValue constructedConstant = constant;
if (constructedConstant.type.element == helpers.jsAnnotationClass) {
ConstantValue value = constructedConstant.fields[nameField];
String name;
if (value.isString) {
StringConstantValue stringValue = value;
backend.nativeDataBuilder
.setJsInteropName(e, stringValue.primitiveValue.slowToString());
name = stringValue.primitiveValue.slowToString();
} else {
// TODO(jacobr): report a warning if the value is not a String.
backend.nativeDataBuilder.setJsInteropName(e, '');
name = '';
}
enabledJsInterop = true;
return;
return name;
}
}
return null;
}
bool hasAnonymousAnnotation(Element element) {
@@ -94,7 +97,7 @@ class JsInteropAnalysis {
});
}
void _checkFunctionParameters(FunctionElement fn) {
void _checkFunctionParameters(MethodElement fn) {
if (fn.hasFunctionSignature &&
fn.functionSignature.optionalParametersAreNamed) {
backend.reporter.reportErrorMessage(
@@ -105,17 +108,31 @@ class JsInteropAnalysis {
}
void processJsInteropAnnotationsInLibrary(LibraryElement library) {
processJsInteropAnnotation(library);
String libraryName = processJsInteropAnnotation(library);
if (libraryName != null) {
backend.nativeDataBuilder.setJsInteropLibraryName(library, libraryName);
}
library.implementation.forEachLocalMember((Element element) {
processJsInteropAnnotation(element);
if (element is MethodElement) {
if (!backend.nativeData.isJsInteropMember(element)) return;
_checkFunctionParameters(element);
if (element is MemberElement) {
String memberName = processJsInteropAnnotation(element);
if (memberName != null) {
backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
}
if (element is MethodElement) {
if (!backend.nativeData.isJsInteropMember(element)) return;
_checkFunctionParameters(element);
}
}
if (!element.isClass) return;
ClassElement classElement = element;
String className = processJsInteropAnnotation(classElement);
if (className != null) {
backend.nativeDataBuilder
.setJsInteropClassName(classElement, className);
}
if (!backend.nativeData.isJsInteropClass(classElement)) return;
// Skip classes that are completely unreachable. This should only happen
@@ -133,13 +150,17 @@ class JsInteropAnalysis {
});
}
classElement.forEachMember((ClassElement classElement, Element member) {
processJsInteropAnnotation(member);
classElement
.forEachMember((ClassElement classElement, MemberElement member) {
String memberName = processJsInteropAnnotation(member);
if (memberName != null) {
backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
}
if (!member.isSynthesized &&
backend.nativeData.isJsInteropClass(classElement) &&
member is FunctionElement) {
FunctionElement fn = member;
member is MethodElement) {
MethodElement fn = member;
if (!fn.isExternal &&
!fn.isAbstract &&
!fn.isConstructor &&
@@ -292,7 +292,7 @@ class MinifyNamer extends Namer
}
@override
jsAst.Name instanceFieldPropertyName(Element element) {
jsAst.Name instanceFieldPropertyName(FieldElement element) {
jsAst.Name proposed = _minifiedInstanceFieldPropertyName(element);
if (proposed != null) {
return proposed;
@@ -778,36 +778,6 @@ class Namer {
return invocationName(new Selector.fromElement(method));
}
String _jsNameHelper(Element e) {
String jsInteropName = _nativeData.getJsInteropName(e);
if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
return e.isLibrary ? 'self' : _nativeData.getUnescapedJSInteropName(e.name);
}
/// Returns a JavaScript path specifying the context in which
/// [element.fixedBackendName] should be evaluated. Only applicable for
/// elements using typed JavaScript interop.
/// For example: fixedBackendPath for the static method createMap in the
/// Map class of the goog.map JavaScript library would have path
/// "goog.maps.Map".
String fixedBackendMethodPath(MethodElement element) {
return _fixedBackendPath(element);
}
String _fixedBackendPath(Element element) {
if (!_nativeData.isJsInterop(element)) return null;
if (element.isInstanceMember) return 'this';
if (element.isConstructor) return _fixedBackendPath(element.enclosingClass);
if (element.isLibrary) return 'self';
var sb = new StringBuffer();
sb..write(_jsNameHelper(element.library));
if (element.enclosingClass != null && element.enclosingClass != element) {
sb..write('.')..write(_jsNameHelper(element.enclosingClass));
}
return sb.toString();
}
/// Returns the annotated name for a variant of `call`.
/// The result has the form:
///
+157 -86
View File
@@ -10,7 +10,6 @@ import '../elements/elements.dart'
ClassElement,
Element,
FieldElement,
FunctionElement,
LibraryElement,
MemberElement,
MethodElement;
@@ -63,11 +62,17 @@ abstract class NativeData extends NativeClassData {
/// Returns `true` if the name of [element] is fixed for the generated
/// JavaScript.
bool hasFixedBackendName(Element element);
bool hasFixedBackendName(MemberElement element);
/// Computes the name for [element] to use in the generated JavaScript. This
/// is either given through a native annotation or a js interop annotation.
String getFixedBackendName(Entity entity);
String getFixedBackendName(MemberEntity element);
/// Computes the name prefix for [element] to use in the generated JavaScript.
///
/// For static and top-level members and constructors this is based on the
/// JavaScript names for the library and/or the enclosing class.
String getFixedBackendMethodPath(MethodElement element);
/// Returns the list of non-directive native tag words for [cls].
List<String> getNativeTagsOfClass(ClassElement cls);
@@ -75,22 +80,21 @@ abstract class NativeData extends NativeClassData {
/// Returns `true` if [cls] has a `!nonleaf` tag word.
bool hasNativeTagsForcedNonLeaf(ClassElement cls);
/// Returns `true` if [element] is part of JsInterop.
///
/// Deprecated: Use [isJsInteropLibrary], [isJsInteropClass] or
/// [isJsInteropMember] instead.
@deprecated
bool isJsInterop(Element element);
/// Returns `true` if [element] is a JsInterop method.
bool isJsInteropMember(MethodElement element);
bool isJsInteropMember(MemberEntity element);
/// Returns the explicit js interop name for [element].
String getJsInteropName(Element element);
/// Returns the explicit js interop name for library [element].
String getJsInteropLibraryName(LibraryElement element);
/// Returns the explicit js interop name for class [element].
String getJsInteropClassName(ClassElement element);
/// Returns the explicit js interop name for member [element].
String getJsInteropMemberName(MemberElement element);
/// Apply JS$ escaping scheme to convert possible escaped Dart names into
/// JS names.
String getUnescapedJSInteropName(String name);
String computeUnescapedJSInteropName(String name);
}
abstract class NativeClassDataBuilder {
@@ -131,15 +135,24 @@ abstract class NativeDataBuilder {
/// [element] in the generated JavaScript.
void setNativeMemberName(MemberElement element, String name);
/// Sets the explicit js interop [name] for [element].
void setJsInteropName(Element element, String name);
/// Sets the explicit js interop [name] for the library [element].
void setJsInteropLibraryName(LibraryElement element, String name);
/// Sets the explicit js interop [name] for the class [element].
void setJsInteropClassName(ClassElement element, String name);
/// Sets the explicit js interop [name] for the member [element].
void setJsInteropMemberName(MemberElement element, String name);
}
class NativeDataImpl
implements NativeData, NativeDataBuilder, NativeClassDataBuilder {
/// The JavaScript names for elements implemented via typed JavaScript
/// interop.
Map<Element, String> jsInteropNames = <Element, String>{};
Map<LibraryElement, String> jsInteropLibraryNames =
<LibraryElement, String>{};
Map<ClassElement, String> jsInteropClassNames = <ClassElement, String>{};
Map<MemberElement, String> jsInteropMemberNames = <MemberElement, String>{};
/// The JavaScript names for native JavaScript elements implemented.
Map<Element, String> nativeMemberName = <Element, String>{};
@@ -165,125 +178,183 @@ class NativeDataImpl
static const String _jsInteropEscapePrefix = r'JS$';
/// Returns `true` if [element] is explicitly marked as part of JsInterop.
bool _isJsInterop(Element element) {
return jsInteropNames.containsKey(element.declaration);
bool _isJsInteropLibrary(LibraryElement element) {
return jsInteropLibraryNames.containsKey(element);
}
/// Marks [element] as an explicit part of JsInterop. The js interop name is
/// expected to be computed later.
void markAsJsInterop(Element element) {
jsInteropNames[element.declaration] = null;
/// Returns `true` if [element] is explicitly marked as part of JsInterop.
bool _isJsInteropClass(ClassElement element) {
return jsInteropClassNames.containsKey(element);
}
/// Returns `true` if [element] is explicitly marked as part of JsInterop.
bool _isJsInteropMember(MemberElement element) {
return jsInteropMemberNames.containsKey(element);
}
@override
void markAsJsInteropLibrary(LibraryElement element) {
markAsJsInterop(element);
jsInteropLibraryNames[element] = null;
}
@override
void markAsJsInteropClass(ClassElement element) {
markAsJsInterop(element);
jsInteropClassNames[element] = null;
}
@override
void markAsJsInteropMember(MemberElement element) {
markAsJsInterop(element);
jsInteropMemberNames[element] = null;
}
/// Sets the explicit js interop [name] for [element].
void setJsInteropName(Element element, String name) {
assert(invariant(element, isJsInterop(element),
/// Sets the explicit js interop [name] for the library [element].
void setJsInteropLibraryName(LibraryElement element, String name) {
assert(invariant(element, _isJsInteropLibrary(element),
message:
'Element $element is not js interop but given a js interop name.'));
jsInteropNames[element.declaration] = name;
'Library $element is not js interop but given a js interop name.'));
jsInteropLibraryNames[element] = name;
}
/// Returns the explicit js interop name for [element].
String getJsInteropName(Element element) {
return jsInteropNames[element.declaration];
/// Sets the explicit js interop [name] for the class [element].
void setJsInteropClassName(ClassElement element, String name) {
assert(invariant(element, _isJsInteropClass(element),
message:
'Class $element is not js interop but given a js interop name.'));
jsInteropClassNames[element] = name;
}
/// Returns `true` if [element] is part of JsInterop.
bool isJsInterop(Element element) {
// An function is part of JsInterop in the following cases:
// * It has a jsInteropName annotation
// * It is external member of a class or library tagged as JsInterop.
if (element.isFunction || element.isConstructor || element.isAccessor) {
FunctionElement function = element;
if (!function.isExternal) return false;
/// Sets the explicit js interop [name] for the member [element].
void setJsInteropMemberName(MemberElement element, String name) {
assert(invariant(element, _isJsInteropMember(element),
message:
'Member $element is not js interop but given a js interop name.'));
jsInteropMemberNames[element] = name;
}
if (_isJsInterop(function)) return true;
if (function.isClassMember) return isJsInterop(function.contextClass);
if (function.isTopLevel) return isJsInterop(function.library);
return false;
} else {
return _isJsInterop(element);
}
/// Returns the explicit js interop name for library [element].
String getJsInteropLibraryName(LibraryElement element) {
return jsInteropLibraryNames[element];
}
/// Returns the explicit js interop name for class [element].
String getJsInteropClassName(ClassElement element) {
return jsInteropClassNames[element];
}
/// Returns the explicit js interop name for member [element].
String getJsInteropMemberName(MemberElement element) {
return jsInteropMemberNames[element];
}
/// Returns `true` if [element] is a JsInterop library.
bool isJsInteropLibrary(LibraryElement element) => isJsInterop(element);
bool isJsInteropLibrary(LibraryElement element) =>
_isJsInteropLibrary(element);
/// Returns `true` if [element] is a JsInterop class.
bool isJsInteropClass(ClassElement element) => isJsInterop(element);
bool isJsInteropClass(ClassElement element) => _isJsInteropClass(element);
/// Returns `true` if [element] is a JsInterop method.
bool isJsInteropMember(MethodElement element) => isJsInterop(element);
bool isJsInteropMember(MemberElement element) {
if (element.isFunction || element.isConstructor || element.isAccessor) {
MethodElement function = element;
if (!function.isExternal) return false;
if (_isJsInteropMember(function)) return true;
if (function.isClassMember) {
return _isJsInteropClass(function.enclosingClass);
}
if (function.isTopLevel) {
return _isJsInteropLibrary(function.library);
}
return false;
} else {
return _isJsInteropMember(element);
}
}
/// Returns `true` if the name of [element] is fixed for the generated
/// JavaScript.
bool hasFixedBackendName(Element element) {
return isJsInterop(element) ||
bool hasFixedBackendName(MemberElement element) {
return isJsInteropMember(element) ||
nativeMemberName.containsKey(element.declaration);
}
String _jsNameHelper(Element element) {
String jsInteropName = jsInteropNames[element.declaration];
assert(invariant(element, !(_isJsInterop(element) && jsInteropName == null),
message:
'Element $element is js interop but js interop name has not yet '
'been computed.'));
if (jsInteropName != null && jsInteropName.isNotEmpty) {
return jsInteropName;
}
return element.isLibrary ? 'self' : getUnescapedJSInteropName(element.name);
}
/// Computes the name for [element] to use in the generated JavaScript. This
/// is either given through a native annotation or a js interop annotation.
String getFixedBackendName(Entity entity) {
// TODO(johnniwinther): Remove this assignment from [Entity] to [Element]
// when `.declaration` is no longer needed.
Element element = entity;
String getFixedBackendName(MemberElement element) {
String name = nativeMemberName[element.declaration];
if (name == null && isJsInterop(element)) {
if (name == null && isJsInteropMember(element)) {
// If an element isJsInterop but _isJsInterop is false that means it is
// considered interop as the parent class is interop.
name = _jsNameHelper(
element.isConstructor ? element.enclosingClass : element);
name = element.isConstructor
? _jsClassNameHelper(element.enclosingClass)
: _jsMemberNameHelper(element);
nativeMemberName[element.declaration] = name;
}
return name;
}
/// Whether [element] corresponds to a native JavaScript construct either
/// through the native mechanism (`@Native(...)` or the `native` pseudo
/// keyword) which is only allowed for internal libraries or via the typed
/// JavaScriptInterop mechanism which is allowed for user libraries.
bool isNative(Element element) {
if (isJsInterop(element)) return true;
if (element.isClass) {
return nativeClassTagInfo.containsKey(element.declaration);
} else {
return nativeMemberName.containsKey(element.declaration);
String _jsLibraryNameHelper(LibraryElement element) {
String jsInteropName = getJsInteropLibraryName(element);
if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
return 'self';
}
String _jsClassNameHelper(ClassElement element) {
String jsInteropName = getJsInteropClassName(element);
if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
return computeUnescapedJSInteropName(element.name);
}
String _jsMemberNameHelper(MemberElement element) {
String jsInteropName = jsInteropMemberNames[element];
assert(invariant(element,
!(jsInteropMemberNames.containsKey(element) && jsInteropName == null),
message:
'Member $element is js interop but js interop name has not yet '
'been computed.'));
if (jsInteropName != null && jsInteropName.isNotEmpty) {
return jsInteropName;
}
return computeUnescapedJSInteropName(element.name);
}
/// Returns a JavaScript path specifying the context in which
/// [element.fixedBackendName] should be evaluated. Only applicable for
/// elements using typed JavaScript interop.
/// For example: fixedBackendPath for the static method createMap in the
/// Map class of the goog.map JavaScript library would have path
/// "goog.maps.Map".
String getFixedBackendMethodPath(MethodElement element) {
if (!isJsInteropMember(element)) return null;
if (element.isInstanceMember) return 'this';
if (element.isConstructor) {
return _fixedBackendClassPath(element.enclosingClass);
}
StringBuffer sb = new StringBuffer();
sb.write(_jsLibraryNameHelper(element.library));
if (element.enclosingClass != null) {
sb..write('.')..write(_jsClassNameHelper(element.enclosingClass));
}
return sb.toString();
}
String _fixedBackendClassPath(ClassElement element) {
if (!isJsInteropClass(element)) return null;
return _jsLibraryNameHelper(element.library);
}
/// Returns `true` if [cls] is a native class.
bool isNativeClass(ClassElement element) => isNative(element);
bool isNativeClass(ClassElement element) {
if (isJsInteropClass(element)) return true;
return nativeClassTagInfo.containsKey(element);
}
/// Returns `true` if [element] is a native member of a native class.
bool isNativeMember(MemberElement element) => isNative(element);
bool isNativeMember(MemberElement element) {
if (isJsInteropMember(element)) return true;
return nativeMemberName.containsKey(element);
}
/// Returns `true` if [element] or any of its superclasses is native.
bool isNativeOrExtendsNative(ClassElement element) {
@@ -390,7 +461,7 @@ class NativeDataImpl
/// Apply JS$ escaping scheme to convert possible escaped Dart names into
/// JS names.
String getUnescapedJSInteropName(String name) {
String computeUnescapedJSInteropName(String name) {
return name.startsWith(_jsInteropEscapePrefix)
? name.substring(_jsInteropEscapePrefix.length)
: name;
@@ -339,7 +339,8 @@ class NativeEmitter {
// and library that uses typed JavaScript interop will create only 1
// unique template.
receiver = js
.uncachedExpressionTemplate(namer.fixedBackendMethodPath(member))
.uncachedExpressionTemplate(
nativeData.getFixedBackendMethodPath(member))
.instantiate([]);
} else {
receiver = js('this');
@@ -354,7 +354,7 @@ class ProgramBuilder {
if (e is ClassElement && backend.nativeData.isJsInteropClass(e)) {
e.declaration.forEachMember((_, Element member) {
var jsName =
backend.nativeData.getUnescapedJSInteropName(member.name);
backend.nativeData.computeUnescapedJSInteropName(member.name);
if (!member.isInstanceMember) return;
if (member.isGetter || member.isField || member.isFunction) {
var selectors = worldBuilder.getterInvocationsByName(member.name);
+13 -12
View File
@@ -1067,7 +1067,7 @@ class SsaBuilder extends ast.Visitor
ast.Send call = link.head;
assert(ast.Initializers.isSuperConstructorCall(call) ||
ast.Initializers.isConstructorRedirect(call));
FunctionElement target = elements[call].implementation;
ConstructorElement target = elements[call];
CallStructure callStructure =
elements.getSelector(call).callStructure;
Link<ast.Node> arguments = call.arguments;
@@ -2490,8 +2490,8 @@ class SsaBuilder extends ast.Visitor
* Invariant: [element] must be an implementation element.
*/
List<HInstruction> makeStaticArgumentList(CallStructure callStructure,
Link<ast.Node> arguments, FunctionElement element) {
assert(invariant(element, element.isImplementation));
Link<ast.Node> arguments, MethodElement element) {
assert(invariant(element, element.isDeclaration));
HInstruction compileArgument(ast.Node argument) {
visit(argument);
@@ -2501,7 +2501,7 @@ class SsaBuilder extends ast.Visitor
return Elements.makeArgumentsList<HInstruction>(
callStructure,
arguments,
element,
element.implementation,
compileArgument,
backend.nativeData.isJsInteropMember(element)
? handleConstantForOptionalParameterJsInterop
@@ -3069,8 +3069,8 @@ class SsaBuilder extends ast.Visitor
Selector selector = elements.getSelector(node);
assert(invariant(node, selector.applies(method.implementation),
message: "$selector does not apply to ${method.implementation}"));
List<HInstruction> inputs = makeStaticArgumentList(
selector.callStructure, node.arguments, method.implementation);
List<HInstruction> inputs =
makeStaticArgumentList(selector.callStructure, node.arguments, method);
push(buildInvokeSuper(selector, method, inputs, sourceInformation));
}
@@ -3402,7 +3402,7 @@ class SsaBuilder extends ast.Visitor
inputs.add(graph.addConstantNull(closedWorld));
}
inputs.addAll(makeStaticArgumentList(
callStructure, send.arguments, constructorImplementation));
callStructure, send.arguments, constructorImplementation.declaration));
TypeMask elementType = computeType(constructor);
if (isFixedListConstructorCall) {
@@ -3562,9 +3562,9 @@ class SsaBuilder extends ast.Visitor
/// Generate an invocation to the static or top level [function].
void generateStaticFunctionInvoke(
ast.Send node, FunctionElement function, CallStructure callStructure) {
List<HInstruction> inputs = makeStaticArgumentList(
callStructure, node.arguments, function.implementation);
ast.Send node, MethodElement function, CallStructure callStructure) {
List<HInstruction> inputs =
makeStaticArgumentList(callStructure, node.arguments, function);
pushInvokeStatic(node, function, inputs,
sourceInformation:
@@ -4026,7 +4026,7 @@ class SsaBuilder extends ast.Visitor
if (argument != null) {
filteredArguments.add(argument);
var jsName =
backend.nativeData.getUnescapedJSInteropName(parameter.name);
backend.nativeData.computeUnescapedJSInteropName(parameter.name);
parameterNameMap[jsName] = new js.InterpolatedExpression(positions++);
}
i++;
@@ -4045,7 +4045,8 @@ class SsaBuilder extends ast.Visitor
..sourceInformation = sourceInformation;
}
var target = new HForeignCode(
js.js.parseForeignJS("${backend.namer.fixedBackendMethodPath(element)}."
js.js.parseForeignJS(
"${backend.nativeData.getFixedBackendMethodPath(element)}."
"${backend.nativeData.getFixedBackendName(element)}"),
commonMasks.dynamicType,
<HInstruction>[]);
+8 -1
View File
@@ -206,13 +206,20 @@ class GlobalTypeInferenceResults {
var key = (element is SynthesizedCallMethodElementX)
? element.memberContext
: element;
bool isJsInterop = false;
if (element is MemberElement) {
isJsInterop = _compiler.backend.nativeData.isJsInteropMember(element);
} else if (element is ClassElement) {
// TODO(johnniwinther): Can we meet classes here?
isJsInterop = _compiler.backend.nativeData.isJsInteropClass(element);
}
return _elementResults.putIfAbsent(
element,
() => new GlobalTypeInferenceElementResultImpl(
element,
_inferrer.inferrer.inTreeData[key],
_inferrer,
_compiler.backend.nativeData.isJsInterop(element),
isJsInterop,
dynamicType));
}
@@ -50,8 +50,20 @@ Future checkNativeData(Uri uri, {bool verbose: false}) async {
NativeDataImpl nativeData1 = backend1.nativeData;
NativeDataImpl nativeData2 = backend2.nativeData;
checkMaps(nativeData1.jsInteropNames, nativeData2.jsInteropNames,
"NativeData.jsInteropNames", areElementsEquivalent, equality,
checkMaps(
nativeData1.jsInteropLibraryNames,
nativeData2.jsInteropLibraryNames,
"NativeData.jsInteropLibraryNames",
areElementsEquivalent,
equality,
verbose: verbose);
checkMaps(nativeData1.jsInteropClassNames, nativeData2.jsInteropClassNames,
"NativeData.jsInteropClassNames", areElementsEquivalent, equality,
verbose: verbose);
checkMaps(nativeData1.jsInteropMemberNames, nativeData2.jsInteropMemberNames,
"NativeData.jsInteropMemberNames", areElementsEquivalent, equality,
verbose: verbose);
checkMaps(nativeData1.nativeMemberName, nativeData2.nativeMemberName,