Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart

Issue 1318043005: Support user generated custom native JS classes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ptal Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.js_emitter.program_builder; 5 library dart2js.js_emitter.program_builder;
6 6
7 import '../js_emitter.dart' show computeMixinClass, Emitter; 7 import '../js_emitter.dart' show computeMixinClass, Emitter;
8 import '../model.dart'; 8 import '../model.dart';
9 9
10 import '../../common.dart'; 10 import '../../common.dart';
11 import '../../closure.dart' show ClosureFieldElement; 11 import '../../closure.dart' show ClosureFieldElement;
12 import '../../js/js.dart' as js; 12 import '../../js/js.dart' as js;
13 13
14 import '../../js_backend/js_backend.dart' show 14 import '../../js_backend/js_backend.dart' show
15 Namer, 15 Namer,
16 JavaScriptBackend, 16 JavaScriptBackend,
17 JavaScriptConstantCompiler; 17 JavaScriptConstantCompiler,
18 StringBackedName;
18 19
19 import '../js_emitter.dart' show 20 import '../js_emitter.dart' show
20 ClassStubGenerator, 21 ClassStubGenerator,
21 CodeEmitterTask, 22 CodeEmitterTask,
22 InterceptorStubGenerator, 23 InterceptorStubGenerator,
23 MainCallStubGenerator, 24 MainCallStubGenerator,
24 ParameterStubGenerator, 25 ParameterStubGenerator,
25 RuntimeTypeGenerator, 26 RuntimeTypeGenerator,
26 TypeTestProperties; 27 TypeTestProperties;
27 28
28 import '../../elements/elements.dart' show 29 import '../../elements/elements.dart' show
29 FieldElement, 30 FieldElement,
30 MethodElement, 31 MethodElement,
32 Name,
31 ParameterElement; 33 ParameterElement;
32 34
33 import '../../universe/universe.dart' show Universe, SelectorConstraints; 35 import '../../universe/universe.dart' show Universe, SelectorConstraints;
34 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit; 36 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
35 37
36 part 'collector.dart'; 38 part 'collector.dart';
37 part 'registry.dart'; 39 part 'registry.dart';
38 part 'field_visitor.dart'; 40 part 'field_visitor.dart';
39 41
40 /// Builds a self-contained representation of the program that can then be 42 /// Builds a self-contained representation of the program that can then be
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 Set<ClassElement> interceptorClassesNeededByConstants = 137 Set<ClassElement> interceptorClassesNeededByConstants =
136 collector.computeInterceptorsReferencedFromConstants(); 138 collector.computeInterceptorsReferencedFromConstants();
137 Set<ClassElement> classesModifiedByEmitRTISupport = 139 Set<ClassElement> classesModifiedByEmitRTISupport =
138 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport(); 140 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport();
139 141
140 142
141 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses( 143 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses(
142 nativeClasses, interceptorClassesNeededByConstants, 144 nativeClasses, interceptorClassesNeededByConstants,
143 classesModifiedByEmitRTISupport); 145 classesModifiedByEmitRTISupport);
144 146
147 _addJsInteropStubs(_registry.mainLibrariesMap);
148
145 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap); 149 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap);
146 Iterable<Fragment> deferredFragments = 150 Iterable<Fragment> deferredFragments =
147 _registry.deferredLibrariesMap.map(_buildDeferredFragment); 151 _registry.deferredLibrariesMap.map(_buildDeferredFragment);
148 152
149 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); 153 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount);
150 fragments[0] = mainFragment; 154 fragments[0] = mainFragment;
151 fragments.setAll(1, deferredFragments); 155 fragments.setAll(1, deferredFragments);
152 156
153 _markEagerClasses(); 157 _markEagerClasses();
154 158
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 316
313 List<Library> _buildLibraries(LibrariesMap librariesMap) { 317 List<Library> _buildLibraries(LibrariesMap librariesMap) {
314 List<Library> libraries = new List<Library>(librariesMap.length); 318 List<Library> libraries = new List<Library>(librariesMap.length);
315 int count = 0; 319 int count = 0;
316 librariesMap.forEach((LibraryElement library, List<Element> elements) { 320 librariesMap.forEach((LibraryElement library, List<Element> elements) {
317 libraries[count++] = _buildLibrary(library, elements); 321 libraries[count++] = _buildLibrary(library, elements);
318 }); 322 });
319 return libraries; 323 return libraries;
320 } 324 }
321 325
326 void _addJsInteropStubs(LibrariesMap librariesMap) {
327 if (_classes.containsKey(_compiler.objectClass)) {
328 var toStringInvocation = namer.invocationName(new Selector.call(
329 new Name("toString", _compiler.objectClass.library),
330 CallStructure.NO_ARGS));
331 // TODO(jacobr): register toString as used so that it is always accessible
332 // from JavaScript.
333 _classes[_compiler.objectClass].callStubs.add(_buildStubMethod(
334 new StringBackedName("toString"),
335 js.js('function() { return this.#(this) }', toStringInvocation)));
336 }
337
338 // We add all members from classes marked with isJsInterop to the base
339 // Interceptor class with implementations that directly call the
340 // corresponding JavaScript member. We do not attempt to bind this when
341 // tearing off JavaScript methods as we cannot distinguish between calling
342 // a regular getter that returns a JavaScript function and tearing off
343 // a method in the case where there exist multiple JavaScript classes
344 // that conflict on whether the member is a getter or a method.
345 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 :)
346 var stubNames = new Set<String>();
347 librariesMap.forEach((LibraryElement library, List<Element> elements) {
348 for (Element e in elements) {
349 if (e is ClassElement && e.isJsInterop) {
350 e.declaration.forEachMember((_, Element member) {
351 if (!member.isInstanceMember) return;
352 if (member.isGetter || member.isField || member.isFunction) {
353 var selectors =
354 _compiler.codegenWorld.getterInvocationsByName(member.name);
355 if (selectors != null && !selectors.isEmpty) {
356 for (var selector in selectors.keys) {
357 var stubName = namer.invocationName(selector);
358 if (stubNames.add(stubName.key)) {
359 interceptorClass.callStubs.add(_buildStubMethod(
360 stubName,
361 js.js(
362 'function(obj) { return obj.# }', [member.name]),
363 element: member));
364 }
365 }
366 }
367 }
368
369 if (member.isSetter || (member.isField && !member.isConst)) {
370 var selectors =
371 _compiler.codegenWorld.setterInvocationsByName(member.name);
372 if (selectors != null && !selectors.isEmpty) {
373 var stubName = namer.setterForElement(member);
374 if (stubNames.add(stubName.key)) {
375 interceptorClass.callStubs.add(_buildStubMethod(
376 stubName,
377 js.js('function(obj, v) { return obj.# = v }',
378 [member.name]),
379 element: member));
380 }
381 }
382 }
383
384 if (member.isFunction) {
385 var selectors =
386 _compiler.codegenWorld.invocationsByName(member.name);
387 FunctionElement fn = member;
388 // Named arguments are not yet supported. In the future we
389 // may want to map named arguments to an object literal containing
390 // all named arguments.
391 if (selectors != null && !selectors.isEmpty) {
392 for (var selector in selectors.keys) {
393 // Check whether the arity matches this member.
394 var argumentCount = selector.argumentCount;
395 if (argumentCount > fn.parameters.length) break;
396 if (argumentCount < fn.parameters.length &&
397 !fn.parameters[argumentCount].isOptional) break;
398 var stubName = namer.invocationName(selector);
399 if (!stubNames.add(stubName.key)) break;
400 var candidateParameterNames =
401 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMOPQRSTUVWXYZ';
402 var parameters = new List<String>.generate(argumentCount,
403 (i) => candidateParameterNames[i]);
404
405 interceptorClass.callStubs.add(_buildStubMethod(
406 stubName,
407 js.js('function(receiver, #) { return receiver.#(#) }',
408 [parameters, member.name, parameters]),
409 element: member));
410 }
411 }
412 }
413 });
414 }
415 }
416 });
417 }
418
322 // Note that a library-element may have multiple [Library]s, if it is split 419 // Note that a library-element may have multiple [Library]s, if it is split
323 // into multiple output units. 420 // into multiple output units.
324 Library _buildLibrary(LibraryElement library, List<Element> elements) { 421 Library _buildLibrary(LibraryElement library, List<Element> elements) {
325 String uri = library.canonicalUri.toString(); 422 String uri = library.canonicalUri.toString();
326 423
327 List<StaticMethod> statics = elements 424 List<StaticMethod> statics = elements
328 .where((e) => e is FunctionElement) 425 .where((e) => e is FunctionElement)
329 .map(_buildStaticMethod) 426 .map(_buildStaticMethod)
330 .toList(); 427 .toList();
331 428
(...skipping 27 matching lines...) Expand all
359 456
360 return new Class( 457 return new Class(
361 element, name, null, [], instanceFields, [], [], [], [], [], [], null, 458 element, name, null, [], instanceFields, [], [], [], [], [], [], null,
362 isDirectlyInstantiated: true, 459 isDirectlyInstantiated: true,
363 onlyForRti: false, 460 onlyForRti: false,
364 isNative: element.isNative); 461 isNative: element.isNative);
365 } 462 }
366 463
367 Class _buildClass(ClassElement element) { 464 Class _buildClass(ClassElement element) {
368 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); 465 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
466 if (element.isJsInterop) {
467 // TODO(jacobr): check whether the class has any active static fields
468 // if it does not we can suppress it completely.
469 onlyForRti = true;
470 }
369 471
370 List<Method> methods = []; 472 List<Method> methods = [];
371 List<StubMethod> callStubs = <StubMethod>[]; 473 List<StubMethod> callStubs = <StubMethod>[];
372 474
373 ClassStubGenerator classStubGenerator = 475 ClassStubGenerator classStubGenerator =
374 new ClassStubGenerator(_compiler, namer, backend); 476 new ClassStubGenerator(_compiler, namer, backend);
375 RuntimeTypeGenerator runtimeTypeGenerator = 477 RuntimeTypeGenerator runtimeTypeGenerator =
376 new RuntimeTypeGenerator(_compiler, _task, namer); 478 new RuntimeTypeGenerator(_compiler, _task, namer);
377 479
378 void visitMember(ClassElement enclosing, Element member) { 480 void visitMember(ClassElement enclosing, Element member) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 onlyForRti ? const <Field>[] : _buildFields(element, false); 541 onlyForRti ? const <Field>[] : _buildFields(element, false);
440 List<Field> staticFieldsForReflection = 542 List<Field> staticFieldsForReflection =
441 onlyForRti ? const <Field>[] : _buildFields(element, true); 543 onlyForRti ? const <Field>[] : _buildFields(element, true);
442 544
443 TypeTestProperties typeTests = 545 TypeTestProperties typeTests =
444 runtimeTypeGenerator.generateIsTests( 546 runtimeTypeGenerator.generateIsTests(
445 element, 547 element,
446 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); 548 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
447 549
448 List<StubMethod> checkedSetters = <StubMethod>[]; 550 List<StubMethod> checkedSetters = <StubMethod>[];
449 for (Field field in instanceFields) { 551 List<StubMethod> isChecks = <StubMethod>[];
450 if (field.needsCheckedSetter) { 552 if (element.isJsInterop) {
451 assert(!field.needsUncheckedSetter); 553 typeTests.properties.forEach((js.Name name, js.Node code) {
452 Element element = field.element; 554 _classes[backend.jsInterceptorClass].isChecks.add(
453 js.Expression code = backend.generatedCode[element]; 555 _buildStubMethod(name, code));
454 assert(code != null); 556 });
455 js.Name name = namer.deriveSetterName(field.accessorName); 557 } else {
456 checkedSetters.add(_buildStubMethod(name, code, element: element)); 558 for (Field field in instanceFields) {
559 if (field.needsCheckedSetter) {
560 assert(!field.needsUncheckedSetter);
561 Element element = field.element;
562 js.Expression code = backend.generatedCode[element];
563 assert(code != null);
564 js.Name name = namer.deriveSetterName(field.accessorName);
565 checkedSetters.add(_buildStubMethod(name, code, element: element));
566 }
457 } 567 }
568
569 typeTests.properties.forEach((js.Name name, js.Node code) {
570 isChecks.add(_buildStubMethod(name, code));
571 });
458 } 572 }
459 573
460 List<StubMethod> isChecks = <StubMethod>[];
461 typeTests.properties.forEach((js.Name name, js.Node code) {
462 isChecks.add(_buildStubMethod(name, code));
463 });
464
465 js.Name name = namer.className(element); 574 js.Name name = namer.className(element);
466 String holderName = namer.globalObjectFor(element); 575 String holderName = namer.globalObjectFor(element);
467 // TODO(floitsch): we shouldn't update the registry in the middle of 576 // TODO(floitsch): we shouldn't update the registry in the middle of
468 // building a class. 577 // building a class.
469 Holder holder = _registry.registerHolder(holderName); 578 Holder holder = _registry.registerHolder(holderName);
470 bool isInstantiated = 579 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.
471 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); 580 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
472 581
473 Class result; 582 Class result;
474 if (element.isMixinApplication && !onlyForRti) { 583 if (element.isMixinApplication && !onlyForRti) {
475 assert(!element.isNative); 584 assert(!element.isNative);
476 assert(methods.isEmpty); 585 assert(methods.isEmpty);
477 586
478 result = new MixinApplication(element, 587 result = new MixinApplication(element,
479 name, holder, 588 name, holder,
480 instanceFields, 589 instanceFields,
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 Constant constant = new Constant(name, holder, constantValue); 938 Constant constant = new Constant(name, holder, constantValue);
830 _constants[constantValue] = constant; 939 _constants[constantValue] = constant;
831 } 940 }
832 } 941 }
833 942
834 Holder _registerStaticStateHolder() { 943 Holder _registerStaticStateHolder() {
835 return _registry.registerHolder( 944 return _registry.registerHolder(
836 namer.staticStateHolder, isStaticStateHolder: true); 945 namer.staticStateHolder, isStaticStateHolder: true);
837 } 946 }
838 } 947 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698