Chromium Code Reviews| 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, ReceiverMaskSet; | 35 import '../../universe/universe.dart' show Universe, ReceiverMaskSet; |
| 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 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 194 return loadMap; | 196 return loadMap; |
| 195 } | 197 } |
| 196 | 198 |
| 197 js.Expression _buildTypeToInterceptorMap() { | 199 js.Expression _buildTypeToInterceptorMap() { |
| 198 InterceptorStubGenerator stubGenerator = | 200 InterceptorStubGenerator stubGenerator = |
| 199 new InterceptorStubGenerator(_compiler, namer, backend); | 201 new InterceptorStubGenerator(_compiler, namer, backend); |
| 200 return stubGenerator.generateTypeToInterceptorMap(); | 202 return stubGenerator.generateTypeToInterceptorMap(); |
| 201 } | 203 } |
| 202 | 204 |
| 203 MainFragment _buildMainFragment(LibrariesMap librariesMap) { | 205 MainFragment _buildMainFragment(LibrariesMap librariesMap) { |
| 206 _buildJsInteropStubs(librariesMap); | |
| 204 // Construct the main output from the libraries and the registered holders. | 207 // Construct the main output from the libraries and the registered holders. |
| 205 MainFragment result = new MainFragment( | 208 MainFragment result = new MainFragment( |
| 206 librariesMap.outputUnit, | 209 librariesMap.outputUnit, |
| 207 "", // The empty string is the name for the main output file. | 210 "", // The empty string is the name for the main output file. |
| 208 _buildInvokeMain(), | 211 _buildInvokeMain(), |
| 209 _buildLibraries(librariesMap), | 212 _buildLibraries(librariesMap), |
| 210 _buildStaticNonFinalFields(librariesMap), | 213 _buildStaticNonFinalFields(librariesMap), |
| 211 _buildStaticLazilyInitializedFields(librariesMap), | 214 _buildStaticLazilyInitializedFields(librariesMap), |
| 212 _buildConstants(librariesMap)); | 215 _buildConstants(librariesMap)); |
| 213 _outputs[librariesMap.outputUnit] = result; | 216 _outputs[librariesMap.outputUnit] = result; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 | 315 |
| 313 List<Library> _buildLibraries(LibrariesMap librariesMap) { | 316 List<Library> _buildLibraries(LibrariesMap librariesMap) { |
| 314 List<Library> libraries = new List<Library>(librariesMap.length); | 317 List<Library> libraries = new List<Library>(librariesMap.length); |
| 315 int count = 0; | 318 int count = 0; |
| 316 librariesMap.forEach((LibraryElement library, List<Element> elements) { | 319 librariesMap.forEach((LibraryElement library, List<Element> elements) { |
| 317 libraries[count++] = _buildLibrary(library, elements); | 320 libraries[count++] = _buildLibrary(library, elements); |
| 318 }); | 321 }); |
| 319 return libraries; | 322 return libraries; |
| 320 } | 323 } |
| 321 | 324 |
| 325 void _buildJsInteropStubs(LibrariesMap librariesMap) { | |
| 326 if (_classes.containsKey(_compiler.objectClass)) { | |
| 327 var toStringInvocation = namer.invocationName(new Selector.call( | |
| 328 new Name("toString", _compiler.objectClass.library), | |
| 329 CallStructure.NO_ARGS)); | |
| 330 // TODO(jacobr): register toString as used so that it is always accessible | |
| 331 // from JavaScript. | |
| 332 _classes[_compiler.objectClass].callStubs.add(_buildStubMethod( | |
| 333 new StringBackedName("toString"), | |
| 334 js.js('function() { return this.#(this) }', toStringInvocation))); | |
| 335 } | |
| 336 | |
| 337 // We add all members from classes marked with isJsInterop to the base | |
| 338 // Interceptor class with implementations that directly call the | |
| 339 // corresponding JavaScript member. We do not attempt to bind this when | |
| 340 // tearing off JavaScript methods as we cannot distinguish between calling | |
| 341 // a regular getter that returns a JavaScript function and tearing off | |
| 342 // a method in the case where there exist multiple JavaScript classes | |
| 343 // that conflict on whether the member is a getter or a method. | |
| 344 var interceptorClass = _classes[backend.jsInterceptorClass]; | |
| 345 var stubNames = new Set<String>(); | |
| 346 librariesMap.forEach((LibraryElement library, List<Element> elements) { | |
| 347 for (Element e in elements) { | |
| 348 if (e is ClassElement && e.isJsInterop) { | |
| 349 e.declaration.forEachMember((_, Element member) { | |
| 350 if (!member.isInstanceMember) return; | |
| 351 if (member.isGetter || member.isField || member.isFunction) { | |
| 352 var selectors = | |
| 353 _compiler.codegenWorld.getterInvocationsByName(member.name); | |
| 354 if (selectors != null && !selectors.isEmpty) { | |
| 355 for (var selector in selectors.keys) { | |
| 356 var stubName = namer.invocationName(selector); | |
| 357 if (stubNames.add(stubName.key)) { | |
| 358 interceptorClass.callStubs.add(_buildStubMethod( | |
| 359 stubName, | |
| 360 js.js( | |
| 361 'function(obj) { return obj.# }', [member.name]), | |
| 362 element: member)); | |
| 363 } | |
| 364 } | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 if (member.isSetter || (member.isField && !member.isConst)) { | |
| 369 var selectors = | |
| 370 _compiler.codegenWorld.setterInvocationsByName(member.name); | |
| 371 if (selectors != null && !selectors.isEmpty) { | |
| 372 var stubName = namer.setterForElement(member); | |
| 373 if (stubNames.add(stubName.key)) { | |
| 374 interceptorClass.callStubs.add(_buildStubMethod( | |
| 375 stubName, | |
| 376 js.js('function(obj, v) { return obj.# = v }', | |
| 377 [member.name]), | |
| 378 element: member)); | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 if (member.isFunction) { | |
| 384 var selectors = | |
| 385 _compiler.codegenWorld.invocationsByName(member.name); | |
| 386 FunctionElement fn = member; | |
| 387 // Named arguments are not yet supported. In the future we | |
| 388 // may want to map named arguments to an object literal containing | |
| 389 // all named arguments. | |
| 390 if (selectors != null && !selectors.isEmpty) { | |
| 391 for (var selector in selectors.keys) { | |
| 392 // Check whether the arity matches this member. | |
| 393 var argumentCount = selector.argumentCount; | |
| 394 if (argumentCount > fn.parameters.length) break; | |
| 395 if (argumentCount < fn.parameters.length && | |
| 396 !fn.parameters[argumentCount].isOptional) break; | |
| 397 var stubName = namer.invocationName(selector); | |
| 398 if (!stubNames.add(stubName.key)) break; | |
| 399 var parameters = <js.Parameter>[]; | |
| 400 for (var i = 0; i < argumentCount; i++) { | |
| 401 parameters.add( | |
| 402 new js.Parameter(new String.fromCharCode(97 + i))); | |
| 403 } | |
| 404 interceptorClass.callStubs.add(_buildStubMethod( | |
| 405 stubName, | |
| 406 js.js('function(obj, #) { return obj.#(#) }', | |
| 407 [parameters, member.name, parameters]), | |
| 408 element: member)); | |
| 409 } | |
| 410 } | |
| 411 } | |
| 412 }); | |
| 413 } | |
| 414 } | |
| 415 }); | |
| 416 } | |
| 417 | |
| 322 // Note that a library-element may have multiple [Library]s, if it is split | 418 // Note that a library-element may have multiple [Library]s, if it is split |
| 323 // into multiple output units. | 419 // into multiple output units. |
| 324 Library _buildLibrary(LibraryElement library, List<Element> elements) { | 420 Library _buildLibrary(LibraryElement library, List<Element> elements) { |
| 325 String uri = library.canonicalUri.toString(); | 421 String uri = library.canonicalUri.toString(); |
| 326 | 422 |
| 327 List<StaticMethod> statics = elements | 423 List<StaticMethod> statics = elements |
| 328 .where((e) => e is FunctionElement) | 424 .where((e) => e is FunctionElement) |
| 329 .map(_buildStaticMethod) | 425 .map(_buildStaticMethod) |
| 330 .toList(); | 426 .toList(); |
| 331 | 427 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 359 | 455 |
| 360 return new Class( | 456 return new Class( |
| 361 element, name, null, [], instanceFields, [], [], [], [], [], [], null, | 457 element, name, null, [], instanceFields, [], [], [], [], [], [], null, |
| 362 isDirectlyInstantiated: true, | 458 isDirectlyInstantiated: true, |
| 363 onlyForRti: false, | 459 onlyForRti: false, |
| 364 isNative: element.isNative); | 460 isNative: element.isNative); |
| 365 } | 461 } |
| 366 | 462 |
| 367 Class _buildClass(ClassElement element) { | 463 Class _buildClass(ClassElement element) { |
| 368 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); | 464 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); |
| 465 bool onlyJsInterop = element.isJsInterop; | |
| 466 if (onlyJsInterop) { | |
| 467 // TODO(jacobr): check whether the class has any active static fields | |
| 468 // if it does not we can suppress it completelly. | |
| 469 onlyForRti = true; // XXX is this right? | |
| 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); |
|
alexandre.ardhuin
2015/09/03 20:14:11
There are some strange indentations in the rest of
| |
| 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) { |
| 379 assert(invariant(element, member.isDeclaration)); | 481 assert(invariant(element, member.isDeclaration)); |
| 380 assert(invariant(element, element == enclosing)); | 482 assert(invariant(element, element == enclosing)); |
| 381 | 483 |
| 382 if (Elements.isNonAbstractInstanceMember(member)) { | 484 if (Elements.isNonAbstractInstanceMember(member)) { |
| 383 // TODO(herhut): Remove once _buildMethod can no longer return null. | 485 // TODO(herhut): Remove once _buildMethod can no longer return null. |
| 384 Method method = _buildMethod(member); | 486 Method method = _buildMethod(member); |
| 385 if (method != null) methods.add(method); | 487 if (method != null) methods.add(method); |
| 386 } | 488 } |
| 387 if (member.isGetter || member.isField) { | 489 if (member.isGetter || member.isField) { |
| 388 Map<Selector, ReceiverMaskSet> selectors = | 490 Map<Selector, ReceiverMaskSet> selectors = |
| 389 _compiler.codegenWorld.invocationsByName(member.name); | 491 _compiler.codegenWorld.invocationsByName(member.name); |
| 390 if (selectors != null && !selectors.isEmpty) { | 492 if (selectors != null && !selectors.isEmpty) { |
| 391 | 493 |
| 392 Map<js.Name, js.Expression> callStubsForMember = | 494 Map<js.Name, js.Expression> callStubsForMember = |
| 393 classStubGenerator.generateCallStubsForGetter(member, selectors); | 495 classStubGenerator.generateCallStubsForGetter(member, selectors); |
| 394 callStubsForMember.forEach((js.Name name, js.Expression code) { | 496 callStubsForMember.forEach((js.Name name, js.Expression code) { |
| 395 callStubs.add(_buildStubMethod(name, code, element: member)); | 497 callStubs.add(_buildStubMethod(name, code, element: member)); |
| 396 }); | 498 }); |
| 397 } | 499 } |
| 398 } | 500 } |
| 399 } | 501 } |
| 400 | 502 |
| 401 List<StubMethod> typeVariableReaderStubs = | 503 List<StubMethod> typeVariableReaderStubs = |
| 402 runtimeTypeGenerator.generateTypeVariableReaderStubs(element); | 504 runtimeTypeGenerator.generateTypeVariableReaderStubs(element); |
| 403 | 505 |
| 404 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; | 506 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; |
| 405 | 507 |
| 406 if (backend.enabledNoSuchMethod && element == _compiler.objectClass) { | 508 if (backend.enabledNoSuchMethod && element == _compiler.objectClass) { |
| 407 Map<js.Name, Selector> selectors = | 509 Map<js.Name, Selector> selectors = |
| 408 classStubGenerator.computeSelectorsForNsmHandlers(); | 510 classStubGenerator.computeSelectorsForNsmHandlers(); |
| 409 selectors.forEach((js.Name name, Selector selector) { | 511 selectors.forEach((js.Name name, Selector selector) { |
| 410 // If the program contains `const Symbol` names we have to retain them. | 512 // If the program contains `const Symbol` names we have to retain them. |
| 411 String selectorName = selector.name; | 513 String selectorName = selector.name; |
| 412 if (selector.isSetter) selectorName = "$selectorName="; | 514 if (selector.isSetter) selectorName = "$selectorName="; |
| 413 if (backend.symbolsUsed.contains(selectorName)) { | 515 if (backend.symbolsUsed.contains(selectorName)) { |
| 414 _symbolsMap[name] = selectorName; | 516 _symbolsMap[name] = selectorName; |
| 415 } | 517 } |
| 416 noSuchMethodStubs | 518 noSuchMethodStubs |
| 417 .add(classStubGenerator.generateStubForNoSuchMethod(name, | 519 .add(classStubGenerator.generateStubForNoSuchMethod(name, |
| 418 selector)); | 520 selector)); |
| 419 }); | 521 }); |
| 420 } | 522 } |
| 421 | 523 |
| 422 if (element == backend.closureClass) { | 524 if (element == backend.closureClass) { |
| 423 // We add a special getter here to allow for tearing off a closure from | 525 // We add a special getter here to allow for tearing off a closure from |
| 424 // itself. | 526 // itself. |
| 425 js.Name name = namer.getterForMember(Selector.CALL_NAME); | 527 js.Name name = namer.getterForMember(Selector.CALL_NAME); |
| 426 js.Fun function = js.js('function() { return this; }'); | 528 js.Fun function = js.js('function() { return this; }'); |
| 427 callStubs.add(_buildStubMethod(name, function)); | 529 callStubs.add(_buildStubMethod(name, function)); |
| 428 } | 530 } |
| 429 | 531 |
| 430 ClassElement implementation = element.implementation; | 532 ClassElement implementation = element.implementation; |
| 431 | 533 |
| 432 // MixinApplications run through the members of their mixin. Here, we are | 534 // MixinApplications run through the members of their mixin. Here, we are |
| 433 // only interested in direct members. | 535 // only interested in direct members. |
| 434 if (!onlyForRti && !element.isMixinApplication) { | 536 if (!onlyForRti && !element.isMixinApplication) { |
| 435 implementation.forEachMember(visitMember, includeBackendMembers: true); | 537 implementation.forEachMember(visitMember, includeBackendMembers: true); |
| 436 } | 538 } |
| 437 | 539 |
| 438 List<Field> instanceFields = | 540 List<Field> instanceFields = |
| 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 (!onlyJsInterop) { |
| 451 assert(!field.needsUncheckedSetter); | 553 for (Field field in instanceFields) { |
| 452 Element element = field.element; | 554 if (field.needsCheckedSetter) { |
| 453 js.Expression code = backend.generatedCode[element]; | 555 assert(!field.needsUncheckedSetter); |
| 454 assert(code != null); | 556 Element element = field.element; |
| 455 js.Name name = namer.deriveSetterName(field.accessorName); | 557 js.Expression code = backend.generatedCode[element]; |
| 456 checkedSetters.add(_buildStubMethod(name, code, element: element)); | 558 assert(code != null); |
| 559 js.Name name = namer.deriveSetterName(field.accessorName); | |
| 560 checkedSetters.add(_buildStubMethod(name, code, element: element)); | |
| 561 } | |
| 457 } | 562 } |
| 563 | |
| 564 typeTests.properties.forEach((js.Name name, js.Node code) { | |
| 565 isChecks.add(_buildStubMethod(name, code)); | |
| 566 }); | |
| 458 } | 567 } |
| 459 | 568 if (element.isJsInterop) { |
| 460 List<StubMethod> isChecks = <StubMethod>[]; | 569 // TODO(jacobr): make sure we aren't adding the same is checks multiple ti mes.. |
| 461 typeTests.properties.forEach((js.Name name, js.Node code) { | 570 typeTests.properties.forEach((js.Name name, js.Node code) { |
| 462 isChecks.add(_buildStubMethod(name, code)); | 571 _classes[backend.jsInterceptorClass].isChecks.add(_buildStubMethod(name, code)); |
| 463 }); | 572 }); |
| 573 } | |
| 464 | 574 |
| 465 js.Name name = namer.className(element); | 575 js.Name name = namer.className(element); |
| 466 String holderName = namer.globalObjectFor(element); | 576 String holderName = namer.globalObjectFor(element); |
| 467 // TODO(floitsch): we shouldn't update the registry in the middle of | 577 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 468 // building a class. | 578 // building a class. |
| 469 Holder holder = _registry.registerHolder(holderName); | 579 Holder holder = _registry.registerHolder(holderName); |
| 470 bool isInstantiated = | 580 bool isInstantiated = onlyJsInterop ? false : |
| 471 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 581 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| 472 | 582 |
| 473 Class result; | 583 Class result; |
| 474 if (element.isMixinApplication && !onlyForRti) { | 584 if (element.isMixinApplication && !onlyForRti) { |
| 475 assert(!element.isNative); | 585 assert(!element.isNative); |
| 476 assert(methods.isEmpty); | 586 assert(methods.isEmpty); |
| 477 | 587 |
| 478 result = new MixinApplication(element, | 588 result = new MixinApplication(element, |
| 479 name, holder, | 589 name, holder, |
| 480 instanceFields, | 590 instanceFields, |
| 481 staticFieldsForReflection, | 591 staticFieldsForReflection, |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 829 Constant constant = new Constant(name, holder, constantValue); | 939 Constant constant = new Constant(name, holder, constantValue); |
| 830 _constants[constantValue] = constant; | 940 _constants[constantValue] = constant; |
| 831 } | 941 } |
| 832 } | 942 } |
| 833 | 943 |
| 834 Holder _registerStaticStateHolder() { | 944 Holder _registerStaticStateHolder() { |
| 835 return _registry.registerHolder( | 945 return _registry.registerHolder( |
| 836 namer.staticStateHolder, isStaticStateHolder: true); | 946 namer.staticStateHolder, isStaticStateHolder: true); |
| 837 } | 947 } |
| 838 } | 948 } |
| OLD | NEW |