OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |