| 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 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 Loading... |
| 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 Loading... |
| 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.jsJavaScriptObjectClass]; |
| 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 Loading... |
| 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 Loading... |
| 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 && |
| 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 Loading... |
| 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 } |
| OLD | NEW |