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

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: about to land 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 7 import '../js_emitter.dart' show
8 ClassStubGenerator, 8 ClassStubGenerator,
9 CodeEmitterTask, 9 CodeEmitterTask,
10 computeMixinClass, 10 computeMixinClass,
(...skipping 19 matching lines...) Expand all
30 DartType; 30 DartType;
31 import '../../elements/elements.dart' show 31 import '../../elements/elements.dart' show
32 ClassElement, 32 ClassElement,
33 Element, 33 Element,
34 Elements, 34 Elements,
35 FieldElement, 35 FieldElement,
36 FunctionElement, 36 FunctionElement,
37 FunctionSignature, 37 FunctionSignature,
38 LibraryElement, 38 LibraryElement,
39 MethodElement, 39 MethodElement,
40 Name,
40 ParameterElement, 41 ParameterElement,
41 TypedefElement, 42 TypedefElement,
42 VariableElement; 43 VariableElement;
43 import '../../js/js.dart' as js; 44 import '../../js/js.dart' as js;
44 import '../../js_backend/js_backend.dart' show 45 import '../../js_backend/js_backend.dart' show
45 Namer, 46 Namer,
46 JavaScriptBackend, 47 JavaScriptBackend,
47 JavaScriptConstantCompiler; 48 JavaScriptConstantCompiler,
49 StringBackedName;
50 import '../../universe/call_structure.dart' show
51 CallStructure;
48 import '../../universe/selector.dart' show 52 import '../../universe/selector.dart' show
49 Selector; 53 Selector;
50 import '../../universe/universe.dart' show 54 import '../../universe/universe.dart' show
51 Universe, 55 Universe,
52 SelectorConstraints; 56 SelectorConstraints;
53 import '../../deferred_load.dart' show 57 import '../../deferred_load.dart' show
54 DeferredLoadTask, 58 DeferredLoadTask,
55 OutputUnit; 59 OutputUnit;
56 60
57 part 'collector.dart'; 61 part 'collector.dart';
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 Set<ClassElement> interceptorClassesNeededByConstants = 160 Set<ClassElement> interceptorClassesNeededByConstants =
157 collector.computeInterceptorsReferencedFromConstants(); 161 collector.computeInterceptorsReferencedFromConstants();
158 Set<ClassElement> classesModifiedByEmitRTISupport = 162 Set<ClassElement> classesModifiedByEmitRTISupport =
159 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport(); 163 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport();
160 164
161 165
162 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses( 166 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses(
163 nativeClasses, interceptorClassesNeededByConstants, 167 nativeClasses, interceptorClassesNeededByConstants,
164 classesModifiedByEmitRTISupport); 168 classesModifiedByEmitRTISupport);
165 169
170 _addJsInteropStubs(_registry.mainLibrariesMap);
171
166 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap); 172 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap);
167 Iterable<Fragment> deferredFragments = 173 Iterable<Fragment> deferredFragments =
168 _registry.deferredLibrariesMap.map(_buildDeferredFragment); 174 _registry.deferredLibrariesMap.map(_buildDeferredFragment);
169 175
170 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); 176 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount);
171 fragments[0] = mainFragment; 177 fragments[0] = mainFragment;
172 fragments.setAll(1, deferredFragments); 178 fragments.setAll(1, deferredFragments);
173 179
174 _markEagerClasses(); 180 _markEagerClasses();
175 181
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 339
334 List<Library> _buildLibraries(LibrariesMap librariesMap) { 340 List<Library> _buildLibraries(LibrariesMap librariesMap) {
335 List<Library> libraries = new List<Library>(librariesMap.length); 341 List<Library> libraries = new List<Library>(librariesMap.length);
336 int count = 0; 342 int count = 0;
337 librariesMap.forEach((LibraryElement library, List<Element> elements) { 343 librariesMap.forEach((LibraryElement library, List<Element> elements) {
338 libraries[count++] = _buildLibrary(library, elements); 344 libraries[count++] = _buildLibrary(library, elements);
339 }); 345 });
340 return libraries; 346 return libraries;
341 } 347 }
342 348
349 void _addJsInteropStubs(LibrariesMap librariesMap) {
350 if (_classes.containsKey(_compiler.objectClass)) {
351 var toStringInvocation = namer.invocationName(new Selector.call(
352 new Name("toString", _compiler.objectClass.library),
353 CallStructure.NO_ARGS));
354 // TODO(jacobr): register toString as used so that it is always accessible
355 // from JavaScript.
356 _classes[_compiler.objectClass].callStubs.add(_buildStubMethod(
357 new StringBackedName("toString"),
358 js.js('function() { return this.#(this) }', toStringInvocation)));
359 }
360
361 // We add all members from classes marked with isJsInterop to the base
362 // Interceptor class with implementations that directly call the
363 // corresponding JavaScript member. We do not attempt to bind this when
364 // tearing off JavaScript methods as we cannot distinguish between calling
365 // a regular getter that returns a JavaScript function and tearing off
366 // a method in the case where there exist multiple JavaScript classes
367 // that conflict on whether the member is a getter or a method.
368 var interceptorClass = _classes[backend.jsJavaScriptObjectClass];
369 var stubNames = new Set<String>();
370 librariesMap.forEach((LibraryElement library, List<Element> elements) {
371 for (Element e in elements) {
372 if (e is ClassElement && e.isJsInterop) {
373 e.declaration.forEachMember((_, Element member) {
374 if (!member.isInstanceMember) return;
375 if (member.isGetter || member.isField || member.isFunction) {
376 var selectors =
377 _compiler.codegenWorld.getterInvocationsByName(member.name);
378 if (selectors != null && !selectors.isEmpty) {
379 for (var selector in selectors.keys) {
380 var stubName = namer.invocationName(selector);
381 if (stubNames.add(stubName.key)) {
382 interceptorClass.callStubs.add(_buildStubMethod(
383 stubName,
384 js.js(
385 'function(obj) { return obj.# }', [member.name]),
386 element: member));
387 }
388 }
389 }
390 }
391
392 if (member.isSetter || (member.isField && !member.isConst)) {
393 var selectors =
394 _compiler.codegenWorld.setterInvocationsByName(member.name);
395 if (selectors != null && !selectors.isEmpty) {
396 var stubName = namer.setterForElement(member);
397 if (stubNames.add(stubName.key)) {
398 interceptorClass.callStubs.add(_buildStubMethod(
399 stubName,
400 js.js('function(obj, v) { return obj.# = v }',
401 [member.name]),
402 element: member));
403 }
404 }
405 }
406
407 if (member.isFunction) {
408 var selectors =
409 _compiler.codegenWorld.invocationsByName(member.name);
410 FunctionElement fn = member;
411 // Named arguments are not yet supported. In the future we
412 // may want to map named arguments to an object literal containing
413 // all named arguments.
414 if (selectors != null && !selectors.isEmpty) {
415 for (var selector in selectors.keys) {
416 // Check whether the arity matches this member.
417 var argumentCount = selector.argumentCount;
418 if (argumentCount > fn.parameters.length) break;
419 if (argumentCount < fn.parameters.length &&
420 !fn.parameters[argumentCount].isOptional) break;
421 var stubName = namer.invocationName(selector);
422 if (!stubNames.add(stubName.key)) break;
423 var candidateParameterNames =
424 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMOPQRSTUVWXYZ';
425 var parameters = new List<String>.generate(argumentCount,
426 (i) => candidateParameterNames[i]);
427
428 interceptorClass.callStubs.add(_buildStubMethod(
429 stubName,
430 js.js('function(receiver, #) { return receiver.#(#) }',
431 [parameters, member.name, parameters]),
432 element: member));
433 }
434 }
435 }
436 });
437 }
438 }
439 });
440 }
441
343 // Note that a library-element may have multiple [Library]s, if it is split 442 // Note that a library-element may have multiple [Library]s, if it is split
344 // into multiple output units. 443 // into multiple output units.
345 Library _buildLibrary(LibraryElement library, List<Element> elements) { 444 Library _buildLibrary(LibraryElement library, List<Element> elements) {
346 String uri = library.canonicalUri.toString(); 445 String uri = library.canonicalUri.toString();
347 446
348 List<StaticMethod> statics = elements 447 List<StaticMethod> statics = elements
349 .where((e) => e is FunctionElement) 448 .where((e) => e is FunctionElement)
350 .map(_buildStaticMethod) 449 .map(_buildStaticMethod)
351 .toList(); 450 .toList();
352 451
(...skipping 27 matching lines...) Expand all
380 479
381 return new Class( 480 return new Class(
382 element, name, null, [], instanceFields, [], [], [], [], [], [], null, 481 element, name, null, [], instanceFields, [], [], [], [], [], [], null,
383 isDirectlyInstantiated: true, 482 isDirectlyInstantiated: true,
384 onlyForRti: false, 483 onlyForRti: false,
385 isNative: element.isNative); 484 isNative: element.isNative);
386 } 485 }
387 486
388 Class _buildClass(ClassElement element) { 487 Class _buildClass(ClassElement element) {
389 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); 488 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
489 if (element.isJsInterop) {
490 // TODO(jacobr): check whether the class has any active static fields
491 // if it does not we can suppress it completely.
492 onlyForRti = true;
493 }
390 494
391 List<Method> methods = []; 495 List<Method> methods = [];
392 List<StubMethod> callStubs = <StubMethod>[]; 496 List<StubMethod> callStubs = <StubMethod>[];
393 497
394 ClassStubGenerator classStubGenerator = 498 ClassStubGenerator classStubGenerator =
395 new ClassStubGenerator(_compiler, namer, backend); 499 new ClassStubGenerator(_compiler, namer, backend);
396 RuntimeTypeGenerator runtimeTypeGenerator = 500 RuntimeTypeGenerator runtimeTypeGenerator =
397 new RuntimeTypeGenerator(_compiler, _task, namer); 501 new RuntimeTypeGenerator(_compiler, _task, namer);
398 502
399 void visitMember(ClassElement enclosing, Element member) { 503 void visitMember(ClassElement enclosing, Element member) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 onlyForRti ? const <Field>[] : _buildFields(element, false); 564 onlyForRti ? const <Field>[] : _buildFields(element, false);
461 List<Field> staticFieldsForReflection = 565 List<Field> staticFieldsForReflection =
462 onlyForRti ? const <Field>[] : _buildFields(element, true); 566 onlyForRti ? const <Field>[] : _buildFields(element, true);
463 567
464 TypeTestProperties typeTests = 568 TypeTestProperties typeTests =
465 runtimeTypeGenerator.generateIsTests( 569 runtimeTypeGenerator.generateIsTests(
466 element, 570 element,
467 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); 571 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
468 572
469 List<StubMethod> checkedSetters = <StubMethod>[]; 573 List<StubMethod> checkedSetters = <StubMethod>[];
470 for (Field field in instanceFields) { 574 List<StubMethod> isChecks = <StubMethod>[];
471 if (field.needsCheckedSetter) { 575 if (element.isJsInterop) {
472 assert(!field.needsUncheckedSetter); 576 typeTests.properties.forEach((js.Name name, js.Node code) {
473 Element element = field.element; 577 _classes[backend.jsInterceptorClass].isChecks.add(
474 js.Expression code = backend.generatedCode[element]; 578 _buildStubMethod(name, code));
475 assert(code != null); 579 });
476 js.Name name = namer.deriveSetterName(field.accessorName); 580 } else {
477 checkedSetters.add(_buildStubMethod(name, code, element: element)); 581 for (Field field in instanceFields) {
582 if (field.needsCheckedSetter) {
583 assert(!field.needsUncheckedSetter);
584 Element element = field.element;
585 js.Expression code = backend.generatedCode[element];
586 assert(code != null);
587 js.Name name = namer.deriveSetterName(field.accessorName);
588 checkedSetters.add(_buildStubMethod(name, code, element: element));
589 }
478 } 590 }
591
592 typeTests.properties.forEach((js.Name name, js.Node code) {
593 isChecks.add(_buildStubMethod(name, code));
594 });
479 } 595 }
480 596
481 List<StubMethod> isChecks = <StubMethod>[];
482 typeTests.properties.forEach((js.Name name, js.Node code) {
483 isChecks.add(_buildStubMethod(name, code));
484 });
485
486 js.Name name = namer.className(element); 597 js.Name name = namer.className(element);
487 String holderName = namer.globalObjectFor(element); 598 String holderName = namer.globalObjectFor(element);
488 // TODO(floitsch): we shouldn't update the registry in the middle of 599 // TODO(floitsch): we shouldn't update the registry in the middle of
489 // building a class. 600 // building a class.
490 Holder holder = _registry.registerHolder(holderName); 601 Holder holder = _registry.registerHolder(holderName);
491 bool isInstantiated = 602 bool isInstantiated = !element.isJsInterop &&
492 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); 603 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
493 604
494 Class result; 605 Class result;
495 if (element.isMixinApplication && !onlyForRti) { 606 if (element.isMixinApplication && !onlyForRti) {
496 assert(!element.isNative); 607 assert(!element.isNative);
497 assert(methods.isEmpty); 608 assert(methods.isEmpty);
498 609
499 result = new MixinApplication(element, 610 result = new MixinApplication(element,
500 name, holder, 611 name, holder,
501 instanceFields, 612 instanceFields,
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 Constant constant = new Constant(name, holder, constantValue); 961 Constant constant = new Constant(name, holder, constantValue);
851 _constants[constantValue] = constant; 962 _constants[constantValue] = constant;
852 } 963 }
853 } 964 }
854 965
855 Holder _registerStaticStateHolder() { 966 Holder _registerStaticStateHolder() {
856 return _registry.registerHolder( 967 return _registry.registerHolder(
857 namer.staticStateHolder, isStaticStateHolder: true); 968 namer.staticStateHolder, isStaticStateHolder: true);
858 } 969 }
859 } 970 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/native_emitter.dart ('k') | pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698