Chromium Code Reviews| Index: pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart |
| diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart |
| index 54e15f9a6fbb0cbd1fb990d6130fdd8f23d65d49..4f36fd96d6c2ab28e7b406d5d3c5823bbedb1215 100644 |
| --- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart |
| +++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart |
| @@ -14,7 +14,8 @@ import '../../js/js.dart' as js; |
| import '../../js_backend/js_backend.dart' show |
| Namer, |
| JavaScriptBackend, |
| - JavaScriptConstantCompiler; |
| + JavaScriptConstantCompiler, |
| + StringBackedName; |
| import '../js_emitter.dart' show |
| ClassStubGenerator, |
| @@ -28,6 +29,7 @@ import '../js_emitter.dart' show |
| import '../../elements/elements.dart' show |
| FieldElement, |
| MethodElement, |
| + Name, |
| ParameterElement; |
| import '../../universe/universe.dart' show Universe, SelectorConstraints; |
| @@ -142,6 +144,8 @@ class ProgramBuilder { |
| nativeClasses, interceptorClassesNeededByConstants, |
| classesModifiedByEmitRTISupport); |
| + _addJsInteropStubs(_registry.mainLibrariesMap); |
| + |
| MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap); |
| Iterable<Fragment> deferredFragments = |
| _registry.deferredLibrariesMap.map(_buildDeferredFragment); |
| @@ -319,6 +323,99 @@ class ProgramBuilder { |
| return libraries; |
| } |
| + void _addJsInteropStubs(LibrariesMap librariesMap) { |
| + if (_classes.containsKey(_compiler.objectClass)) { |
| + var toStringInvocation = namer.invocationName(new Selector.call( |
| + new Name("toString", _compiler.objectClass.library), |
| + CallStructure.NO_ARGS)); |
| + // TODO(jacobr): register toString as used so that it is always accessible |
| + // from JavaScript. |
| + _classes[_compiler.objectClass].callStubs.add(_buildStubMethod( |
| + new StringBackedName("toString"), |
| + js.js('function() { return this.#(this) }', toStringInvocation))); |
| + } |
| + |
| + // We add all members from classes marked with isJsInterop to the base |
| + // Interceptor class with implementations that directly call the |
| + // corresponding JavaScript member. We do not attempt to bind this when |
| + // tearing off JavaScript methods as we cannot distinguish between calling |
| + // a regular getter that returns a JavaScript function and tearing off |
| + // a method in the case where there exist multiple JavaScript classes |
| + // that conflict on whether the member is a getter or a method. |
| + var interceptorClass = _classes[backend.jsInterceptorClass]; |
|
sra1
2015/10/06 21:42:17
Add them to jsJavaScriptObjectClass.
Otherwise you
Jacob
2015/10/13 01:19:23
I thought you would complain about that. done :)
|
| + var stubNames = new Set<String>(); |
| + librariesMap.forEach((LibraryElement library, List<Element> elements) { |
| + for (Element e in elements) { |
| + if (e is ClassElement && e.isJsInterop) { |
| + e.declaration.forEachMember((_, Element member) { |
| + if (!member.isInstanceMember) return; |
| + if (member.isGetter || member.isField || member.isFunction) { |
| + var selectors = |
| + _compiler.codegenWorld.getterInvocationsByName(member.name); |
| + if (selectors != null && !selectors.isEmpty) { |
| + for (var selector in selectors.keys) { |
| + var stubName = namer.invocationName(selector); |
| + if (stubNames.add(stubName.key)) { |
| + interceptorClass.callStubs.add(_buildStubMethod( |
| + stubName, |
| + js.js( |
| + 'function(obj) { return obj.# }', [member.name]), |
| + element: member)); |
| + } |
| + } |
| + } |
| + } |
| + |
| + if (member.isSetter || (member.isField && !member.isConst)) { |
| + var selectors = |
| + _compiler.codegenWorld.setterInvocationsByName(member.name); |
| + if (selectors != null && !selectors.isEmpty) { |
| + var stubName = namer.setterForElement(member); |
| + if (stubNames.add(stubName.key)) { |
| + interceptorClass.callStubs.add(_buildStubMethod( |
| + stubName, |
| + js.js('function(obj, v) { return obj.# = v }', |
| + [member.name]), |
| + element: member)); |
| + } |
| + } |
| + } |
| + |
| + if (member.isFunction) { |
| + var selectors = |
| + _compiler.codegenWorld.invocationsByName(member.name); |
| + FunctionElement fn = member; |
| + // Named arguments are not yet supported. In the future we |
| + // may want to map named arguments to an object literal containing |
| + // all named arguments. |
| + if (selectors != null && !selectors.isEmpty) { |
| + for (var selector in selectors.keys) { |
| + // Check whether the arity matches this member. |
| + var argumentCount = selector.argumentCount; |
| + if (argumentCount > fn.parameters.length) break; |
| + if (argumentCount < fn.parameters.length && |
| + !fn.parameters[argumentCount].isOptional) break; |
| + var stubName = namer.invocationName(selector); |
| + if (!stubNames.add(stubName.key)) break; |
| + var candidateParameterNames = |
| + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMOPQRSTUVWXYZ'; |
| + var parameters = new List<String>.generate(argumentCount, |
| + (i) => candidateParameterNames[i]); |
| + |
| + interceptorClass.callStubs.add(_buildStubMethod( |
| + stubName, |
| + js.js('function(receiver, #) { return receiver.#(#) }', |
| + [parameters, member.name, parameters]), |
| + element: member)); |
| + } |
| + } |
| + } |
| + }); |
| + } |
| + } |
| + }); |
| + } |
| + |
| // Note that a library-element may have multiple [Library]s, if it is split |
| // into multiple output units. |
| Library _buildLibrary(LibraryElement library, List<Element> elements) { |
| @@ -366,6 +463,11 @@ class ProgramBuilder { |
| Class _buildClass(ClassElement element) { |
| bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); |
| + if (element.isJsInterop) { |
| + // TODO(jacobr): check whether the class has any active static fields |
| + // if it does not we can suppress it completely. |
| + onlyForRti = true; |
| + } |
| List<Method> methods = []; |
| List<StubMethod> callStubs = <StubMethod>[]; |
| @@ -446,28 +548,35 @@ class ProgramBuilder { |
| storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); |
| List<StubMethod> checkedSetters = <StubMethod>[]; |
| - for (Field field in instanceFields) { |
| - if (field.needsCheckedSetter) { |
| - assert(!field.needsUncheckedSetter); |
| - Element element = field.element; |
| - js.Expression code = backend.generatedCode[element]; |
| - assert(code != null); |
| - js.Name name = namer.deriveSetterName(field.accessorName); |
| - checkedSetters.add(_buildStubMethod(name, code, element: element)); |
| + List<StubMethod> isChecks = <StubMethod>[]; |
| + if (element.isJsInterop) { |
| + typeTests.properties.forEach((js.Name name, js.Node code) { |
| + _classes[backend.jsInterceptorClass].isChecks.add( |
| + _buildStubMethod(name, code)); |
| + }); |
| + } else { |
| + for (Field field in instanceFields) { |
| + if (field.needsCheckedSetter) { |
| + assert(!field.needsUncheckedSetter); |
| + Element element = field.element; |
| + js.Expression code = backend.generatedCode[element]; |
| + assert(code != null); |
| + js.Name name = namer.deriveSetterName(field.accessorName); |
| + checkedSetters.add(_buildStubMethod(name, code, element: element)); |
| + } |
| } |
| - } |
| - List<StubMethod> isChecks = <StubMethod>[]; |
| - typeTests.properties.forEach((js.Name name, js.Node code) { |
| - isChecks.add(_buildStubMethod(name, code)); |
| - }); |
| + typeTests.properties.forEach((js.Name name, js.Node code) { |
| + isChecks.add(_buildStubMethod(name, code)); |
| + }); |
| + } |
| js.Name name = namer.className(element); |
| String holderName = namer.globalObjectFor(element); |
| // TODO(floitsch): we shouldn't update the registry in the middle of |
| // building a class. |
| Holder holder = _registry.registerHolder(holderName); |
| - bool isInstantiated = |
| + bool isInstantiated = element.isJsInterop ? false : |
|
Siggi Cherem (dart-lang)
2015/10/06 22:38:02
x ? false : y
=>
!x && y
Jacob
2015/10/13 01:19:23
Done.
|
| _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| Class result; |