From fd81ba456925b1bb825f4bee2f13b4bbcdcf4f97 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Thu, 10 Aug 2017 10:13:19 +0200 Subject: [PATCH] Support jsinterop/world_test from .dill R=sigmund@google.com Review-Url: https://codereview.chromium.org/2995643002 . --- .../lib/src/js_backend/native_data.dart | 24 ++++++++++++++++- pkg/compiler/lib/src/kernel/element_map.dart | 5 ++-- .../lib/src/kernel/element_map_mixins.dart | 15 ++++++++--- .../lib/src/kernel/native_basic_data.dart | 27 ++++++++++++++----- pkg/compiler/lib/src/ssa/kernel_impact.dart | 8 ++++++ .../dart2js/jsinterop/world_test.dart | 7 ++--- .../compiler/dart2js/kernel/impact_test.dart | 13 ++++++--- 7 files changed, 79 insertions(+), 20 deletions(-) diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart index 8f96de0b86c..05d21bd8ca0 100644 --- a/pkg/compiler/lib/src/js_backend/native_data.dart +++ b/pkg/compiler/lib/src/js_backend/native_data.dart @@ -291,9 +291,31 @@ class NativeBasicDataImpl implements NativeBasicData { return jsInteropClasses.containsKey(element); } + bool _isJsInteropMember(MemberEntity element) { + return jsInteropMembers.containsKey(element); + } + @override bool isJsInteropMember(MemberEntity element) { - return jsInteropMembers.containsKey(element); + // TODO(johnniwinther): Share this with [NativeDataImpl.isJsInteropMember]. + if (element.isFunction || + element.isConstructor || + element.isGetter || + element.isSetter) { + FunctionEntity function = element; + if (!function.isExternal) return false; + + if (_isJsInteropMember(function)) return true; + if (function.enclosingClass != null) { + return isJsInteropClass(function.enclosingClass); + } + if (function.isTopLevel) { + return isJsInteropLibrary(function.library); + } + return false; + } else { + return _isJsInteropMember(element); + } } @override diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart index dfb5a2296a7..3f97d399cb4 100644 --- a/pkg/compiler/lib/src/kernel/element_map.dart +++ b/pkg/compiler/lib/src/kernel/element_map.dart @@ -142,8 +142,9 @@ abstract class KernelToElementMapForImpact extends KernelToElementMap { /// Computes the native behavior for writing to the native [field]. native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field); - /// Computes the native behavior for calling [procedure]. - native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure, + /// Computes the native behavior for calling the function or constructor + /// [member]. + native.NativeBehavior getNativeBehaviorForMethod(ir.Member member, {bool isJsInterop}); /// Compute the kind of foreign helper function called by [node], if any. diff --git a/pkg/compiler/lib/src/kernel/element_map_mixins.dart b/pkg/compiler/lib/src/kernel/element_map_mixins.dart index 8b30d0b6871..e8b50b37d01 100644 --- a/pkg/compiler/lib/src/kernel/element_map_mixins.dart +++ b/pkg/compiler/lib/src/kernel/element_map_mixins.dart @@ -402,12 +402,19 @@ abstract class KernelToElementMapForImpactMixin return nativeBehaviorBuilder.buildFieldStoreBehavior(type); } - /// Computes the native behavior for calling [procedure]. + /// Computes the native behavior for calling [member]. // TODO(johnniwinther): Cache this for later use. - native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure, + native.NativeBehavior getNativeBehaviorForMethod(ir.Member member, {bool isJsInterop}) { - DartType type = getFunctionType(procedure.function); - List metadata = getMetadata(procedure.annotations); + DartType type; + if (member is ir.Procedure) { + type = getFunctionType(member.function); + } else if (member is ir.Constructor) { + type = getFunctionType(member.function); + } else { + failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected method node $member."); + } + List metadata = getMetadata(member.annotations); return nativeBehaviorBuilder.buildMethodBehavior( type, metadata, typeLookup(resolveAsRaw: false), isJsInterop: isJsInterop); diff --git a/pkg/compiler/lib/src/kernel/native_basic_data.dart b/pkg/compiler/lib/src/kernel/native_basic_data.dart index c8463018189..ec07f7a6a79 100644 --- a/pkg/compiler/lib/src/kernel/native_basic_data.dart +++ b/pkg/compiler/lib/src/kernel/native_basic_data.dart @@ -129,18 +129,33 @@ class KernelAnnotationProcessor implements AnnotationProcessor { {'cls': cls.name, 'member': member.name}); } - if (function is ConstructorEntity && - function.isFactoryConstructor && - isAnonymous) { - if (function.parameterStructure.requiredParameters > 0) { + checkFunctionParameters(function); + }); + elementEnvironment.forEachConstructor(cls, + (ConstructorEntity constructor) { + String memberName = getJsInteropName( + library, elementEnvironment.getMemberMetadata(constructor)); + if (memberName != null) { + _nativeBasicDataBuilder.markAsJsInteropMember( + constructor, memberName); + } + + if (!constructor.isExternal) { + reporter.reportErrorMessage( + constructor, + MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, + {'cls': cls.name, 'member': constructor.name}); + } + if (constructor.isFactoryConstructor && isAnonymous) { + if (constructor.parameterStructure.requiredParameters > 0) { reporter.reportErrorMessage( - function, + constructor, MessageKind .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS, {'cls': cls.name}); } } else { - checkFunctionParameters(function); + checkFunctionParameters(constructor); } }); } diff --git a/pkg/compiler/lib/src/ssa/kernel_impact.dart b/pkg/compiler/lib/src/ssa/kernel_impact.dart index 3fd5548e4bb..8540e88e719 100644 --- a/pkg/compiler/lib/src/ssa/kernel_impact.dart +++ b/pkg/compiler/lib/src/ssa/kernel_impact.dart @@ -137,6 +137,14 @@ class KernelImpactBuilder extends ir.Visitor { handleSignature(constructor.function, checkReturnType: false); visitNodes(constructor.initializers); visitNode(constructor.function.body); + if (constructor.isExternal && + !elementAdapter.isForeignLibrary(constructor.enclosingLibrary)) { + MemberEntity member = elementAdapter.getMember(constructor); + bool isJsInterop = + elementAdapter.nativeBasicData.isJsInteropMember(member); + impactBuilder.registerNativeData(elementAdapter + .getNativeBehaviorForMethod(constructor, isJsInterop: isJsInterop)); + } return impactBuilder; } diff --git a/tests/compiler/dart2js/jsinterop/world_test.dart b/tests/compiler/dart2js/jsinterop/world_test.dart index 0af271e42f0..10f945f88c1 100644 --- a/tests/compiler/dart2js/jsinterop/world_test.dart +++ b/tests/compiler/dart2js/jsinterop/world_test.dart @@ -15,11 +15,12 @@ import '../type_test_helper.dart'; void main() { asyncTest(() async { - await testClasses(); + await testClasses(CompileMode.memory); + await testClasses(CompileMode.dill); }); } -testClasses() async { +testClasses(CompileMode compileMode) async { test(String mainSource, {List directlyInstantiated: const [], List abstractlyInstantiated: const [], @@ -77,7 +78,7 @@ newF() => new F(5); import 'package:js/js.dart'; $mainSource -""", compileMode: CompileMode.memory); +""", compileMode: compileMode); Map classEnvironment = {}; ClassEntity registerClass(ClassEntity cls) { diff --git a/tests/compiler/dart2js/kernel/impact_test.dart b/tests/compiler/dart2js/kernel/impact_test.dart index 9608e0068a3..b27cacbcc86 100644 --- a/tests/compiler/dart2js/kernel/impact_test.dart +++ b/tests/compiler/dart2js/kernel/impact_test.dart @@ -30,9 +30,6 @@ import 'test_helpers.dart'; const Map SOURCE = const { // Pretend this is a dart2js_native test to allow use of 'native' keyword. 'sdk/tests/compiler/dart2js_native/main.dart': r''' -@JS() -library test; - import 'dart:_foreign_helper' as foreign show JS; import 'dart:_foreign_helper' hide JS; import 'dart:_js_helper'; @@ -44,8 +41,8 @@ import 'dart:html_common'; import 'dart:math'; import 'dart:typed_data'; import 'dart:web_sql'; -import 'package:js/js.dart'; import 'helper.dart'; +import 'jsinterop.dart'; main() { testEmpty(); @@ -698,12 +695,20 @@ testMixinInstantiation() => new Sub(); testNamedMixinInstantiation() => new NamedMixin(); testGenericMixinInstantiation() => new GenericSub(); testGenericNamedMixinInstantiation() => new GenericNamedMixin(); +''', + 'sdk/tests/compiler/dart2js_native/jsinterop.dart': ''' +@JS() +library jsinterop; + +import 'package:js/js.dart'; @JS() external int testJsInteropMethod(); @JS() class JsInteropClass { + external JsInteropClass(); + @JS() external double method(); }