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; | 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 '../closure.dart' show ClosureFieldElement; | |
| 19 | |
| 20 import 'js_emitter.dart' as emitterTask show | 18 import 'js_emitter.dart' as emitterTask show |
| 21 CodeEmitterTask, | 19 CodeEmitterTask, |
| 22 Emitter, | 20 Emitter, |
| 23 InterceptorStubGenerator, | 21 InterceptorStubGenerator, |
| 24 TypeTestGenerator, | 22 TypeTestGenerator, |
| 25 TypeTestProperties; | 23 TypeTestProperties; |
| 26 | 24 |
| 27 import '../universe/universe.dart' show Universe; | 25 import '../universe/universe.dart' show Universe; |
| 28 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit; | 26 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit; |
| 29 | 27 |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 if (library == backend.interceptorsLibrary) { | 248 if (library == backend.interceptorsLibrary) { |
| 251 statics.addAll(_generateGetInterceptorMethods()); | 249 statics.addAll(_generateGetInterceptorMethods()); |
| 252 statics.addAll(_generateOneShotInterceptors()); | 250 statics.addAll(_generateOneShotInterceptors()); |
| 253 } | 251 } |
| 254 | 252 |
| 255 List<Class> classes = elements | 253 List<Class> classes = elements |
| 256 .where((e) => e is ClassElement) | 254 .where((e) => e is ClassElement) |
| 257 .map(_buildClass) | 255 .map(_buildClass) |
| 258 .toList(growable: false); | 256 .toList(growable: false); |
| 259 | 257 |
| 260 return new Library(library, uri, statics, classes); | 258 bool visitStatics = true; |
| 259 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics); | |
| 260 | |
| 261 return new Library(library, uri, statics, classes, | |
| 262 staticFieldsForReflection); | |
| 261 } | 263 } |
| 262 | 264 |
| 263 Class _buildClass(ClassElement element) { | 265 Class _buildClass(ClassElement element) { |
| 266 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); | |
| 267 | |
| 264 List<Method> methods = []; | 268 List<Method> methods = []; |
| 265 List<InstanceField> fields = []; | |
| 266 | 269 |
| 267 void visitMember(ClassElement enclosing, Element member) { | 270 void visitMember(ClassElement enclosing, Element member) { |
| 268 assert(invariant(element, member.isDeclaration)); | 271 assert(invariant(element, member.isDeclaration)); |
| 269 assert(invariant(element, element == enclosing)); | 272 assert(invariant(element, element == enclosing)); |
| 270 | 273 |
| 271 if (Elements.isNonAbstractInstanceMember(member)) { | 274 if (Elements.isNonAbstractInstanceMember(member)) { |
| 272 js.Expression code = backend.generatedCode[member]; | 275 js.Expression code = backend.generatedCode[member]; |
| 273 // TODO(kasperl): Figure out under which conditions code is null. | 276 // TODO(kasperl): Figure out under which conditions code is null. |
| 274 if (code != null) methods.add(_buildMethod(member, code)); | 277 if (code != null) methods.add(_buildMethod(member, code)); |
| 275 } else if (member.isField && !member.isStatic) { | |
| 276 fields.add(_buildInstanceField(member, enclosing)); | |
| 277 } | 278 } |
| 278 } | 279 } |
| 279 | 280 |
| 280 ClassElement implementation = element.implementation; | 281 ClassElement implementation = element.implementation; |
| 281 | 282 |
| 282 // MixinApplications run through the members of their mixin. Here, we are | 283 // MixinApplications run through the members of their mixin. Here, we are |
| 283 // only interested in direct members. | 284 // only interested in direct members. |
| 284 if (!element.isMixinApplication) { | 285 if (!element.isMixinApplication) { |
| 285 implementation.forEachMember(visitMember, includeBackendMembers: true); | 286 implementation.forEachMember(visitMember, includeBackendMembers: true); |
| 286 } | 287 } |
| 287 | 288 |
| 289 List<Field> instanceFields = | |
| 290 onlyForRti ? const <Field>[] : _buildFields(element, false); | |
| 291 List<Field> staticFieldsForReflection = | |
| 292 onlyForRti ? const <Field>[] : _buildFields(element, true); | |
| 293 | |
| 288 emitterTask.TypeTestGenerator generator = | 294 emitterTask.TypeTestGenerator generator = |
| 289 new emitterTask.TypeTestGenerator(_compiler, _task, namer); | 295 new emitterTask.TypeTestGenerator(_compiler, _task, namer); |
| 290 emitterTask.TypeTestProperties typeTests = | 296 emitterTask.TypeTestProperties typeTests = |
| 291 generator.generateIsTests( | 297 generator.generateIsTests( |
| 292 element, | 298 element, |
| 293 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); | 299 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); |
| 294 | 300 |
| 295 List<StubMethod> isChecks = <StubMethod>[]; | 301 List<StubMethod> isChecks = <StubMethod>[]; |
| 296 typeTests.properties.forEach((String name, js.Node code) { | 302 typeTests.properties.forEach((String name, js.Node code) { |
| 297 isChecks.add(_buildStubMethod(name, code)); | 303 isChecks.add(_buildStubMethod(name, code)); |
| 298 }); | 304 }); |
| 299 | 305 |
| 300 String name = namer.getNameOfClass(element); | 306 String name = namer.getNameOfClass(element); |
| 301 String holderName = namer.globalObjectFor(element); | 307 String holderName = namer.globalObjectFor(element); |
| 302 Holder holder = _registry.registerHolder(holderName); | 308 Holder holder = _registry.registerHolder(holderName); |
| 303 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); | |
| 304 bool isInstantiated = | 309 bool isInstantiated = |
| 305 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 310 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| 306 | 311 |
| 307 Class result; | 312 Class result; |
| 308 if (element.isMixinApplication && !onlyForRti) { | 313 if (element.isMixinApplication && !onlyForRti) { |
| 309 assert(!element.isNative); | 314 assert(!element.isNative); |
| 310 assert(methods.isEmpty); | 315 assert(methods.isEmpty); |
| 311 assert(fields.isEmpty); | |
| 312 | 316 |
| 313 result = new MixinApplication(element, | 317 result = new MixinApplication(element, |
| 314 name, holder, isChecks, | 318 name, holder, |
| 319 instanceFields, | |
| 320 staticFieldsForReflection, | |
| 321 isChecks, | |
| 315 typeTests.functionTypeIndex, | 322 typeTests.functionTypeIndex, |
| 316 isDirectlyInstantiated: isInstantiated, | 323 isDirectlyInstantiated: isInstantiated, |
| 317 onlyForRti: onlyForRti); | 324 onlyForRti: onlyForRti); |
| 318 } else { | 325 } else { |
| 319 result = new Class(element, | 326 result = new Class(element, |
| 320 name, holder, methods, fields, isChecks, | 327 name, holder, methods, instanceFields, |
| 328 staticFieldsForReflection, | |
| 329 isChecks, | |
| 321 typeTests.functionTypeIndex, | 330 typeTests.functionTypeIndex, |
| 322 isDirectlyInstantiated: isInstantiated, | 331 isDirectlyInstantiated: isInstantiated, |
| 323 onlyForRti: onlyForRti, | 332 onlyForRti: onlyForRti, |
| 324 isNative: element.isNative); | 333 isNative: element.isNative); |
| 325 } | 334 } |
| 326 _classes[element] = result; | 335 _classes[element] = result; |
| 327 return result; | 336 return result; |
| 328 } | 337 } |
| 329 | 338 |
| 330 Method _buildMethod(FunctionElement element, js.Expression code) { | 339 Method _buildMethod(FunctionElement element, js.Expression code) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 backend.specializedGetInterceptors; | 372 backend.specializedGetInterceptors; |
| 364 List<String> names = specializedGetInterceptors.keys.toList()..sort(); | 373 List<String> names = specializedGetInterceptors.keys.toList()..sort(); |
| 365 return names.map((String name) { | 374 return names.map((String name) { |
| 366 Set<ClassElement> classes = specializedGetInterceptors[name]; | 375 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 367 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 376 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| 368 // TODO(floitsch): compute `needsTearOff`. | 377 // TODO(floitsch): compute `needsTearOff`. |
| 369 return new StaticStubMethod(name, holder, code, needsTearOff: false); | 378 return new StaticStubMethod(name, holder, code, needsTearOff: false); |
| 370 }); | 379 }); |
| 371 } | 380 } |
| 372 | 381 |
| 373 bool _fieldNeedsGetter(VariableElement field) { | 382 List<Field> _buildFields(Element holder, bool visitStatics) { |
|
floitsch
2015/01/22 15:57:39
These predicates were copied from the classEmitter
| |
| 374 assert(field.isField); | 383 List<Field> fields = <Field>[]; |
| 375 if (_fieldAccessNeverThrows(field)) return false; | 384 _task.oldEmitter.classEmitter.visitFields( |
| 376 return backend.shouldRetainGetter(field) | 385 holder, visitStatics, (VariableElement field, |
| 377 || _compiler.codegenWorld.hasInvokedGetter(field, _compiler.world); | 386 String name, |
| 378 } | 387 String accessorName, |
| 388 bool needsGetter, | |
| 389 bool needsSetter, | |
| 390 bool needsCheckedSetter) { | |
| 391 assert(invariant(field, field.isDeclaration)); | |
| 379 | 392 |
| 380 bool _fieldNeedsSetter(VariableElement field) { | 393 int getterFlags = 0; |
| 381 assert(field.isField); | 394 if (needsGetter) { |
| 382 if (_fieldAccessNeverThrows(field)) return false; | 395 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) { |
| 383 return (!field.isFinal && !field.isConst) | 396 getterFlags = 1; |
| 384 && (backend.shouldRetainSetter(field) | 397 } else { |
| 385 || _compiler.codegenWorld.hasInvokedSetter(field, _compiler.world)); | 398 getterFlags += 2; |
| 386 } | 399 // TODO(sra): 'isInterceptorClass' might not be the correct test |
| 400 // for methods forced to use the interceptor convention because | |
| 401 // the method's class was elsewhere mixed-in to an interceptor. | |
| 402 if (!backend.isInterceptorClass(holder)) { | |
| 403 getterFlags += 1; | |
| 404 } | |
| 405 } | |
| 406 } | |
| 387 | 407 |
| 388 // We never access a field in a closure (a captured variable) without knowing | 408 int setterFlags = 0; |
| 389 // that it is there. Therefore we don't need to use a getter (that will throw | 409 if (needsSetter) { |
| 390 // if the getter method is missing), but can always access the field directly. | 410 if (visitStatics || !backend.fieldHasInterceptedSetter(field)) { |
| 391 bool _fieldAccessNeverThrows(VariableElement field) { | 411 setterFlags = 1; |
| 392 return field is ClosureFieldElement; | 412 } else { |
| 393 } | 413 setterFlags += 2; |
| 414 if (!backend.isInterceptorClass(holder)) { | |
| 415 setterFlags += 1; | |
| 416 } | |
| 417 } | |
| 418 } | |
| 394 | 419 |
| 395 InstanceField _buildInstanceField(VariableElement field, | 420 fields.add(new Field(field, name, accessorName, |
| 396 ClassElement holder) { | 421 getterFlags, setterFlags, |
| 397 assert(invariant(field, field.isDeclaration)); | 422 needsCheckedSetter)); |
| 398 String name = namer.fieldPropertyName(field); | 423 }); |
| 399 | 424 |
| 400 int getterFlags = 0; | 425 return fields; |
| 401 if (_fieldNeedsGetter(field)) { | |
| 402 bool isIntercepted = backend.fieldHasInterceptedGetter(field); | |
| 403 if (isIntercepted) { | |
| 404 getterFlags += 2; | |
| 405 if (!backend.isInterceptorClass(holder)) { | |
| 406 getterFlags += 1; | |
| 407 } | |
| 408 } else { | |
| 409 getterFlags = 1; | |
| 410 } | |
| 411 } | |
| 412 | |
| 413 int setterFlags = 0; | |
| 414 if (_fieldNeedsSetter(field)) { | |
| 415 bool isIntercepted = backend.fieldHasInterceptedSetter(field); | |
| 416 if (isIntercepted) { | |
| 417 setterFlags += 2; | |
| 418 if (!backend.isInterceptorClass(holder)) { | |
| 419 setterFlags += 1; | |
| 420 } | |
| 421 } else { | |
| 422 setterFlags = 1; | |
| 423 } | |
| 424 } | |
| 425 | |
| 426 return new InstanceField(field, name, getterFlags, setterFlags); | |
| 427 } | 426 } |
| 428 | 427 |
| 429 Iterable<StaticMethod> _generateOneShotInterceptors() { | 428 Iterable<StaticMethod> _generateOneShotInterceptors() { |
| 430 emitterTask.InterceptorStubGenerator stubGenerator = | 429 emitterTask.InterceptorStubGenerator stubGenerator = |
| 431 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); | 430 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); |
| 432 | 431 |
| 433 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 432 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 434 Holder holder = _registry.registerHolder(holderName); | 433 Holder holder = _registry.registerHolder(holderName); |
| 435 | 434 |
| 436 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); | 435 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 460 _registry.registerConstant(outputUnit, constantValue); | 459 _registry.registerConstant(outputUnit, constantValue); |
| 461 assert(!_constants.containsKey(constantValue)); | 460 assert(!_constants.containsKey(constantValue)); |
| 462 String name = namer.constantName(constantValue); | 461 String name = namer.constantName(constantValue); |
| 463 String constantObject = namer.globalObjectForConstant(constantValue); | 462 String constantObject = namer.globalObjectForConstant(constantValue); |
| 464 Holder holder = _registry.registerHolder(constantObject); | 463 Holder holder = _registry.registerHolder(constantObject); |
| 465 Constant constant = new Constant(name, holder, constantValue); | 464 Constant constant = new Constant(name, holder, constantValue); |
| 466 _constants[constantValue] = constant; | 465 _constants[constantValue] = constant; |
| 467 } | 466 } |
| 468 } | 467 } |
| 469 } | 468 } |
| OLD | NEW |