| 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; | 7 import 'js_emitter.dart' show computeMixinClass; |
| 8 import 'model.dart'; | 8 import 'model.dart'; |
| 9 | 9 |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| 11 import '../js/js.dart' as js; | 11 import '../js/js.dart' as js; |
| 12 | 12 |
| 13 import '../js_backend/js_backend.dart' show | 13 import '../js_backend/js_backend.dart' show |
| 14 Namer, | 14 Namer, |
| 15 JavaScriptBackend, | 15 JavaScriptBackend, |
| 16 JavaScriptConstantCompiler; | 16 JavaScriptConstantCompiler; |
| 17 | 17 |
| 18 import 'js_emitter.dart' as emitterTask show | 18 import 'js_emitter.dart' show |
| 19 ClassStubGenerator, |
| 19 CodeEmitterTask, | 20 CodeEmitterTask, |
| 20 Emitter, | |
| 21 InterceptorStubGenerator, | 21 InterceptorStubGenerator, |
| 22 TypeTestGenerator, | 22 TypeTestGenerator, |
| 23 TypeTestProperties; | 23 TypeTestProperties; |
| 24 | 24 |
| 25 import '../universe/universe.dart' show Universe; | 25 import '../universe/universe.dart' show Universe; |
| 26 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit; | 26 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit; |
| 27 | 27 |
| 28 part 'registry.dart'; | 28 part 'registry.dart'; |
| 29 | 29 |
| 30 class ProgramBuilder { | 30 class ProgramBuilder { |
| 31 final Compiler _compiler; | 31 final Compiler _compiler; |
| 32 final Namer namer; | 32 final Namer namer; |
| 33 final emitterTask.CodeEmitterTask _task; | 33 final CodeEmitterTask _task; |
| 34 | 34 |
| 35 final Registry _registry; | 35 final Registry _registry; |
| 36 | 36 |
| 37 /// True if the program should store function types in the metadata. | 37 /// True if the program should store function types in the metadata. |
| 38 bool _storeFunctionTypesInMetadata = false; | 38 bool _storeFunctionTypesInMetadata = false; |
| 39 | 39 |
| 40 ProgramBuilder(Compiler compiler, | 40 ProgramBuilder(Compiler compiler, |
| 41 this.namer, | 41 this.namer, |
| 42 this._task) | 42 this._task) |
| 43 : this._compiler = compiler, | 43 : this._compiler = compiler, |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics); | 259 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics); |
| 260 | 260 |
| 261 return new Library(library, uri, statics, classes, | 261 return new Library(library, uri, statics, classes, |
| 262 staticFieldsForReflection); | 262 staticFieldsForReflection); |
| 263 } | 263 } |
| 264 | 264 |
| 265 Class _buildClass(ClassElement element) { | 265 Class _buildClass(ClassElement element) { |
| 266 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); | 266 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); |
| 267 | 267 |
| 268 List<Method> methods = []; | 268 List<Method> methods = []; |
| 269 List<StubMethod> callStubs = <StubMethod>[]; |
| 269 | 270 |
| 270 void visitMember(ClassElement enclosing, Element member) { | 271 void visitMember(ClassElement enclosing, Element member) { |
| 271 assert(invariant(element, member.isDeclaration)); | 272 assert(invariant(element, member.isDeclaration)); |
| 272 assert(invariant(element, element == enclosing)); | 273 assert(invariant(element, element == enclosing)); |
| 273 | 274 |
| 274 if (Elements.isNonAbstractInstanceMember(member)) { | 275 if (Elements.isNonAbstractInstanceMember(member)) { |
| 275 js.Expression code = backend.generatedCode[member]; | 276 js.Expression code = backend.generatedCode[member]; |
| 276 // TODO(kasperl): Figure out under which conditions code is null. | 277 // TODO(kasperl): Figure out under which conditions code is null. |
| 277 if (code != null) methods.add(_buildMethod(member, code)); | 278 if (code != null) methods.add(_buildMethod(member, code)); |
| 278 } | 279 } |
| 280 if (member.isGetter || member.isField) { |
| 281 Set<Selector> selectors = |
| 282 _compiler.codegenWorld.invokedNames[member.name]; |
| 283 if (selectors != null && !selectors.isEmpty) { |
| 284 ClassStubGenerator generator = |
| 285 new ClassStubGenerator(_compiler, namer, backend); |
| 286 Map<String, js.Expression> callStubsForMember = |
| 287 generator.generateCallStubsForGetter(member, selectors); |
| 288 callStubsForMember.forEach((String name, js.Expression code) { |
| 289 callStubs.add(_buildStubMethod(name, code, element: member)); |
| 290 }); |
| 291 } |
| 292 } |
| 279 } | 293 } |
| 280 | 294 |
| 281 ClassElement implementation = element.implementation; | 295 ClassElement implementation = element.implementation; |
| 282 | 296 |
| 283 // MixinApplications run through the members of their mixin. Here, we are | 297 // MixinApplications run through the members of their mixin. Here, we are |
| 284 // only interested in direct members. | 298 // only interested in direct members. |
| 285 if (!element.isMixinApplication) { | 299 if (!onlyForRti && !element.isMixinApplication) { |
| 286 implementation.forEachMember(visitMember, includeBackendMembers: true); | 300 implementation.forEachMember(visitMember, includeBackendMembers: true); |
| 287 } | 301 } |
| 288 | 302 |
| 289 List<Field> instanceFields = | 303 List<Field> instanceFields = |
| 290 onlyForRti ? const <Field>[] : _buildFields(element, false); | 304 onlyForRti ? const <Field>[] : _buildFields(element, false); |
| 291 List<Field> staticFieldsForReflection = | 305 List<Field> staticFieldsForReflection = |
| 292 onlyForRti ? const <Field>[] : _buildFields(element, true); | 306 onlyForRti ? const <Field>[] : _buildFields(element, true); |
| 293 | 307 |
| 294 emitterTask.TypeTestGenerator generator = | 308 TypeTestGenerator generator = |
| 295 new emitterTask.TypeTestGenerator(_compiler, _task, namer); | 309 new TypeTestGenerator(_compiler, _task, namer); |
| 296 emitterTask.TypeTestProperties typeTests = | 310 TypeTestProperties typeTests = |
| 297 generator.generateIsTests( | 311 generator.generateIsTests( |
| 298 element, | 312 element, |
| 299 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); | 313 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); |
| 300 | 314 |
| 301 List<StubMethod> isChecks = <StubMethod>[]; | 315 List<StubMethod> isChecks = <StubMethod>[]; |
| 302 typeTests.properties.forEach((String name, js.Node code) { | 316 typeTests.properties.forEach((String name, js.Node code) { |
| 303 isChecks.add(_buildStubMethod(name, code)); | 317 isChecks.add(_buildStubMethod(name, code)); |
| 304 }); | 318 }); |
| 305 | 319 |
| 306 String name = namer.getNameOfClass(element); | 320 String name = namer.getNameOfClass(element); |
| 307 String holderName = namer.globalObjectFor(element); | 321 String holderName = namer.globalObjectFor(element); |
| 308 Holder holder = _registry.registerHolder(holderName); | 322 Holder holder = _registry.registerHolder(holderName); |
| 309 bool isInstantiated = | 323 bool isInstantiated = |
| 310 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 324 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| 311 | 325 |
| 312 Class result; | 326 Class result; |
| 313 if (element.isMixinApplication && !onlyForRti) { | 327 if (element.isMixinApplication && !onlyForRti) { |
| 314 assert(!element.isNative); | 328 assert(!element.isNative); |
| 315 assert(methods.isEmpty); | 329 assert(methods.isEmpty); |
| 316 | 330 |
| 317 result = new MixinApplication(element, | 331 result = new MixinApplication(element, |
| 318 name, holder, | 332 name, holder, |
| 319 instanceFields, | 333 instanceFields, |
| 320 staticFieldsForReflection, | 334 staticFieldsForReflection, |
| 335 callStubs, |
| 321 isChecks, | 336 isChecks, |
| 322 typeTests.functionTypeIndex, | 337 typeTests.functionTypeIndex, |
| 323 isDirectlyInstantiated: isInstantiated, | 338 isDirectlyInstantiated: isInstantiated, |
| 324 onlyForRti: onlyForRti); | 339 onlyForRti: onlyForRti); |
| 325 } else { | 340 } else { |
| 326 result = new Class(element, | 341 result = new Class(element, |
| 327 name, holder, methods, instanceFields, | 342 name, holder, methods, instanceFields, |
| 328 staticFieldsForReflection, | 343 staticFieldsForReflection, |
| 344 callStubs, |
| 329 isChecks, | 345 isChecks, |
| 330 typeTests.functionTypeIndex, | 346 typeTests.functionTypeIndex, |
| 331 isDirectlyInstantiated: isInstantiated, | 347 isDirectlyInstantiated: isInstantiated, |
| 332 onlyForRti: onlyForRti, | 348 onlyForRti: onlyForRti, |
| 333 isNative: element.isNative); | 349 isNative: element.isNative); |
| 334 } | 350 } |
| 335 _classes[element] = result; | 351 _classes[element] = result; |
| 336 return result; | 352 return result; |
| 337 } | 353 } |
| 338 | 354 |
| 339 Method _buildMethod(FunctionElement element, js.Expression code) { | 355 Method _buildMethod(FunctionElement element, js.Expression code) { |
| 340 String name = namer.getNameOfInstanceMember(element); | 356 String name = namer.getNameOfInstanceMember(element); |
| 341 // TODO(floitsch): compute `needsTearOff`. | 357 // TODO(floitsch): compute `needsTearOff`. |
| 342 return new Method(element, name, code, needsTearOff: false); | 358 return new Method(element, name, code, needsTearOff: false); |
| 343 } | 359 } |
| 344 | 360 |
| 345 Method _buildStubMethod(String name, js.Expression code) { | 361 /// Builds a stub method. |
| 362 /// |
| 363 /// Stub methods may have an element that can be used for code-size |
| 364 /// attribution. |
| 365 Method _buildStubMethod(String name, js.Expression code, |
| 366 {Element element}) { |
| 346 // TODO(floitsch): compute `needsTearOff`. | 367 // TODO(floitsch): compute `needsTearOff`. |
| 347 return new StubMethod(name, code, needsTearOff: false); | 368 return new StubMethod(name, code, needsTearOff: false, element: element); |
| 348 } | 369 } |
| 349 | 370 |
| 350 // The getInterceptor methods directly access the prototype of classes. | 371 // The getInterceptor methods directly access the prototype of classes. |
| 351 // We must evaluate these classes eagerly so that the prototype is | 372 // We must evaluate these classes eagerly so that the prototype is |
| 352 // accessible. | 373 // accessible. |
| 353 void _markEagerInterceptorClasses() { | 374 void _markEagerInterceptorClasses() { |
| 354 Map<String, Set<ClassElement>> specializedGetInterceptors = | 375 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 355 backend.specializedGetInterceptors; | 376 backend.specializedGetInterceptors; |
| 356 for (Set<ClassElement> classes in specializedGetInterceptors.values) { | 377 for (Set<ClassElement> classes in specializedGetInterceptors.values) { |
| 357 for (ClassElement element in classes) { | 378 for (ClassElement element in classes) { |
| 358 Class cls = _classes[element]; | 379 Class cls = _classes[element]; |
| 359 if (cls != null) cls.isEager = true; | 380 if (cls != null) cls.isEager = true; |
| 360 } | 381 } |
| 361 } | 382 } |
| 362 } | 383 } |
| 363 | 384 |
| 364 Iterable<StaticMethod> _generateGetInterceptorMethods() { | 385 Iterable<StaticMethod> _generateGetInterceptorMethods() { |
| 365 emitterTask.InterceptorStubGenerator stubGenerator = | 386 InterceptorStubGenerator stubGenerator = |
| 366 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); | 387 new InterceptorStubGenerator(_compiler, namer, backend); |
| 367 | 388 |
| 368 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 389 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 369 Holder holder = _registry.registerHolder(holderName); | 390 Holder holder = _registry.registerHolder(holderName); |
| 370 | 391 |
| 371 Map<String, Set<ClassElement>> specializedGetInterceptors = | 392 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 372 backend.specializedGetInterceptors; | 393 backend.specializedGetInterceptors; |
| 373 List<String> names = specializedGetInterceptors.keys.toList()..sort(); | 394 List<String> names = specializedGetInterceptors.keys.toList()..sort(); |
| 374 return names.map((String name) { | 395 return names.map((String name) { |
| 375 Set<ClassElement> classes = specializedGetInterceptors[name]; | 396 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 376 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 397 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 | 440 |
| 420 fields.add(new Field(field, name, accessorName, | 441 fields.add(new Field(field, name, accessorName, |
| 421 getterFlags, setterFlags, | 442 getterFlags, setterFlags, |
| 422 needsCheckedSetter)); | 443 needsCheckedSetter)); |
| 423 }); | 444 }); |
| 424 | 445 |
| 425 return fields; | 446 return fields; |
| 426 } | 447 } |
| 427 | 448 |
| 428 Iterable<StaticMethod> _generateOneShotInterceptors() { | 449 Iterable<StaticMethod> _generateOneShotInterceptors() { |
| 429 emitterTask.InterceptorStubGenerator stubGenerator = | 450 InterceptorStubGenerator stubGenerator = |
| 430 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); | 451 new InterceptorStubGenerator(_compiler, namer, backend); |
| 431 | 452 |
| 432 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 453 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 433 Holder holder = _registry.registerHolder(holderName); | 454 Holder holder = _registry.registerHolder(holderName); |
| 434 | 455 |
| 435 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); | 456 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); |
| 436 return names.map((String name) { | 457 return names.map((String name) { |
| 437 js.Expression code = stubGenerator.generateOneShotInterceptor(name); | 458 js.Expression code = stubGenerator.generateOneShotInterceptor(name); |
| 438 return new StaticStubMethod(name, holder, code, needsTearOff: false); | 459 return new StaticStubMethod(name, holder, code, needsTearOff: false); |
| 439 }); | 460 }); |
| 440 } | 461 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 459 _registry.registerConstant(outputUnit, constantValue); | 480 _registry.registerConstant(outputUnit, constantValue); |
| 460 assert(!_constants.containsKey(constantValue)); | 481 assert(!_constants.containsKey(constantValue)); |
| 461 String name = namer.constantName(constantValue); | 482 String name = namer.constantName(constantValue); |
| 462 String constantObject = namer.globalObjectForConstant(constantValue); | 483 String constantObject = namer.globalObjectForConstant(constantValue); |
| 463 Holder holder = _registry.registerHolder(constantObject); | 484 Holder holder = _registry.registerHolder(constantObject); |
| 464 Constant constant = new Constant(name, holder, constantValue); | 485 Constant constant = new Constant(name, holder, constantValue); |
| 465 _constants[constantValue] = constant; | 486 _constants[constantValue] = constant; |
| 466 } | 487 } |
| 467 } | 488 } |
| 468 } | 489 } |
| OLD | NEW |