| 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'; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 .toList(growable: false); | 170 .toList(growable: false); |
| 171 } | 171 } |
| 172 | 172 |
| 173 StaticField _buildStaticField(Element element) { | 173 StaticField _buildStaticField(Element element) { |
| 174 JavaScriptConstantCompiler handler = backend.constants; | 174 JavaScriptConstantCompiler handler = backend.constants; |
| 175 ConstantValue initialValue = handler.getInitialValueFor(element).value; | 175 ConstantValue initialValue = handler.getInitialValueFor(element).value; |
| 176 js.Expression code = _task.emitter.constantReference(initialValue); | 176 js.Expression code = _task.emitter.constantReference(initialValue); |
| 177 String name = namer.getNameOfGlobalField(element); | 177 String name = namer.getNameOfGlobalField(element); |
| 178 bool isFinal = false; | 178 bool isFinal = false; |
| 179 bool isLazy = false; | 179 bool isLazy = false; |
| 180 return new StaticField(name, _registry.registerHolder(r'$'), code, | 180 return new StaticField(element, |
| 181 name, _registry.registerHolder(r'$'), code, |
| 181 isFinal, isLazy); | 182 isFinal, isLazy); |
| 182 } | 183 } |
| 183 | 184 |
| 184 List<StaticField> _buildStaticLazilyInitializedFields(Fragment fragment) { | 185 List<StaticField> _buildStaticLazilyInitializedFields(Fragment fragment) { |
| 185 // TODO(floitsch): lazy fields should just be in their respective | 186 // TODO(floitsch): lazy fields should just be in their respective |
| 186 // libraries. | 187 // libraries. |
| 187 if (fragment != _registry.mainFragment) return const <StaticField>[]; | 188 if (fragment != _registry.mainFragment) return const <StaticField>[]; |
| 188 | 189 |
| 189 JavaScriptConstantCompiler handler = backend.constants; | 190 JavaScriptConstantCompiler handler = backend.constants; |
| 190 List<VariableElement> lazyFields = | 191 List<VariableElement> lazyFields = |
| 191 handler.getLazilyInitializedFieldsForEmission(); | 192 handler.getLazilyInitializedFieldsForEmission(); |
| 192 return Elements.sortedByPosition(lazyFields) | 193 return Elements.sortedByPosition(lazyFields) |
| 193 .map(_buildLazyField) | 194 .map(_buildLazyField) |
| 194 .where((field) => field != null) // Happens when the field was unused. | 195 .where((field) => field != null) // Happens when the field was unused. |
| 195 .toList(growable: false); | 196 .toList(growable: false); |
| 196 } | 197 } |
| 197 | 198 |
| 198 StaticField _buildLazyField(Element element) { | 199 StaticField _buildLazyField(Element element) { |
| 199 JavaScriptConstantCompiler handler = backend.constants; | 200 JavaScriptConstantCompiler handler = backend.constants; |
| 200 js.Expression code = backend.generatedCode[element]; | 201 js.Expression code = backend.generatedCode[element]; |
| 201 // The code is null if we ended up not needing the lazily | 202 // The code is null if we ended up not needing the lazily |
| 202 // initialized field after all because of constant folding | 203 // initialized field after all because of constant folding |
| 203 // before code generation. | 204 // before code generation. |
| 204 if (code == null) return null; | 205 if (code == null) return null; |
| 205 | 206 |
| 206 String name = namer.getNameOfGlobalField(element); | 207 String name = namer.getNameOfGlobalField(element); |
| 207 bool isFinal = element.isFinal; | 208 bool isFinal = element.isFinal; |
| 208 bool isLazy = true; | 209 bool isLazy = true; |
| 209 return new StaticField(name, _registry.registerHolder(r'$'), code, | 210 return new StaticField(element, |
| 211 name, _registry.registerHolder(r'$'), code, |
| 210 isFinal, isLazy); | 212 isFinal, isLazy); |
| 211 } | 213 } |
| 212 | 214 |
| 213 List<Library> _buildLibraries(Fragment fragment) { | 215 List<Library> _buildLibraries(Fragment fragment) { |
| 214 List<Library> libraries = new List<Library>(fragment.length); | 216 List<Library> libraries = new List<Library>(fragment.length); |
| 215 int count = 0; | 217 int count = 0; |
| 216 fragment.forEach((LibraryElement library, List<Element> elements) { | 218 fragment.forEach((LibraryElement library, List<Element> elements) { |
| 217 libraries[count++] = _buildLibrary(library, elements); | 219 libraries[count++] = _buildLibrary(library, elements); |
| 218 }); | 220 }); |
| 219 return libraries; | 221 return libraries; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 235 if (library == backend.interceptorsLibrary) { | 237 if (library == backend.interceptorsLibrary) { |
| 236 statics.addAll(_generateGetInterceptorMethods()); | 238 statics.addAll(_generateGetInterceptorMethods()); |
| 237 statics.addAll(_generateOneShotInterceptors()); | 239 statics.addAll(_generateOneShotInterceptors()); |
| 238 } | 240 } |
| 239 | 241 |
| 240 List<Class> classes = elements | 242 List<Class> classes = elements |
| 241 .where((e) => e is ClassElement) | 243 .where((e) => e is ClassElement) |
| 242 .map(_buildClass) | 244 .map(_buildClass) |
| 243 .toList(growable: false); | 245 .toList(growable: false); |
| 244 | 246 |
| 245 return new Library(uri, statics, classes); | 247 return new Library(library, uri, statics, classes); |
| 246 } | 248 } |
| 247 | 249 |
| 248 Class _buildClass(ClassElement element) { | 250 Class _buildClass(ClassElement element) { |
| 249 List<Method> methods = []; | 251 List<Method> methods = []; |
| 250 List<InstanceField> fields = []; | 252 List<InstanceField> fields = []; |
| 251 | 253 |
| 252 void visitMember(ClassElement enclosing, Element member) { | 254 void visitMember(ClassElement enclosing, Element member) { |
| 253 assert(invariant(element, member.isDeclaration)); | 255 assert(invariant(element, member.isDeclaration)); |
| 254 assert(invariant(element, element == enclosing)); | 256 assert(invariant(element, element == enclosing)); |
| 255 | 257 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 278 // At this point a mixin application must not have any methods or fields. | 280 // At this point a mixin application must not have any methods or fields. |
| 279 // Type-tests might be added to mixin applications, too. | 281 // Type-tests might be added to mixin applications, too. |
| 280 assert(!element.isMixinApplication || methods.isEmpty); | 282 assert(!element.isMixinApplication || methods.isEmpty); |
| 281 assert(!element.isMixinApplication || fields.isEmpty); | 283 assert(!element.isMixinApplication || fields.isEmpty); |
| 282 | 284 |
| 283 // TODO(floitsch): we should not add the code here, but have a list of | 285 // TODO(floitsch): we should not add the code here, but have a list of |
| 284 // is/as classes in the Class object. | 286 // is/as classes in the Class object. |
| 285 // The individual emitters should then call the type test generator to | 287 // The individual emitters should then call the type test generator to |
| 286 // generate the code. | 288 // generate the code. |
| 287 typeTests.properties.forEach((String name, js.Node code) { | 289 typeTests.properties.forEach((String name, js.Node code) { |
| 288 methods.add(_buildMethodWithName(name, code)); | 290 methods.add(_buildStubMethod(name, code)); |
| 289 }); | 291 }); |
| 290 | 292 |
| 291 String name = namer.getNameOfClass(element); | 293 String name = namer.getNameOfClass(element); |
| 292 String holderName = namer.globalObjectFor(element); | 294 String holderName = namer.globalObjectFor(element); |
| 293 Holder holder = _registry.registerHolder(holderName); | 295 Holder holder = _registry.registerHolder(holderName); |
| 294 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); | 296 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); |
| 295 bool isInstantiated = | 297 bool isInstantiated = |
| 296 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 298 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| 297 | 299 |
| 298 Class result; | 300 Class result; |
| 299 if (element.isMixinApplication) { | 301 if (element.isMixinApplication) { |
| 300 result = new MixinApplication(name, holder, methods, fields, | 302 result = new MixinApplication(element, |
| 303 name, holder, methods, fields, |
| 301 isDirectlyInstantiated: isInstantiated, | 304 isDirectlyInstantiated: isInstantiated, |
| 302 onlyForRti: onlyForRti); | 305 onlyForRti: onlyForRti); |
| 303 } else { | 306 } else { |
| 304 result = new Class(name, holder, methods, fields, | 307 result = new Class(element, |
| 308 name, holder, methods, fields, |
| 305 isDirectlyInstantiated: isInstantiated, | 309 isDirectlyInstantiated: isInstantiated, |
| 306 onlyForRti: onlyForRti); | 310 onlyForRti: onlyForRti); |
| 307 } | 311 } |
| 308 _classes[element] = result; | 312 _classes[element] = result; |
| 309 return result; | 313 return result; |
| 310 } | 314 } |
| 311 | 315 |
| 312 Method _buildMethod(FunctionElement element, js.Expression code) { | 316 Method _buildMethod(FunctionElement element, js.Expression code) { |
| 313 String name = namer.getNameOfInstanceMember(element); | 317 String name = namer.getNameOfInstanceMember(element); |
| 314 return new Method(name, code); | 318 return new Method(element, name, code); |
| 315 } | 319 } |
| 316 | 320 |
| 317 Method _buildMethodWithName(String name, js.Expression code) { | 321 Method _buildStubMethod(String name, js.Expression code) { |
| 318 return new Method(name, code); | 322 return new StubMethod(name, code); |
| 319 } | 323 } |
| 320 | 324 |
| 321 // The getInterceptor methods directly access the prototype of classes. | 325 // The getInterceptor methods directly access the prototype of classes. |
| 322 // We must evaluate these classes eagerly so that the prototype is | 326 // We must evaluate these classes eagerly so that the prototype is |
| 323 // accessible. | 327 // accessible. |
| 324 void _markEagerInterceptorClasses() { | 328 void _markEagerInterceptorClasses() { |
| 325 Map<String, Set<ClassElement>> specializedGetInterceptors = | 329 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 326 backend.specializedGetInterceptors; | 330 backend.specializedGetInterceptors; |
| 327 for (Set<ClassElement> classes in specializedGetInterceptors.values) { | 331 for (Set<ClassElement> classes in specializedGetInterceptors.values) { |
| 328 for (ClassElement element in classes) { | 332 for (ClassElement element in classes) { |
| 329 Class cls = _classes[element]; | 333 Class cls = _classes[element]; |
| 330 if (cls != null) cls.isEager = true; | 334 if (cls != null) cls.isEager = true; |
| 331 } | 335 } |
| 332 } | 336 } |
| 333 } | 337 } |
| 334 | 338 |
| 335 Iterable<StaticMethod> _generateGetInterceptorMethods() { | 339 Iterable<StaticMethod> _generateGetInterceptorMethods() { |
| 336 emitterTask.InterceptorStubGenerator stubGenerator = | 340 emitterTask.InterceptorStubGenerator stubGenerator = |
| 337 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); | 341 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); |
| 338 | 342 |
| 339 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 343 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 340 Holder holder = _registry.registerHolder(holderName); | 344 Holder holder = _registry.registerHolder(holderName); |
| 341 | 345 |
| 342 Map<String, Set<ClassElement>> specializedGetInterceptors = | 346 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 343 backend.specializedGetInterceptors; | 347 backend.specializedGetInterceptors; |
| 344 List<String> names = specializedGetInterceptors.keys.toList()..sort(); | 348 List<String> names = specializedGetInterceptors.keys.toList()..sort(); |
| 345 return names.map((String name) { | 349 return names.map((String name) { |
| 346 Set<ClassElement> classes = specializedGetInterceptors[name]; | 350 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 347 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 351 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| 348 return new StaticMethod(name, holder, code); | 352 return new StaticStubMethod(name, holder, code); |
| 349 }); | 353 }); |
| 350 } | 354 } |
| 351 | 355 |
| 352 bool _fieldNeedsGetter(VariableElement field) { | 356 bool _fieldNeedsGetter(VariableElement field) { |
| 353 assert(field.isField); | 357 assert(field.isField); |
| 354 if (_fieldAccessNeverThrows(field)) return false; | 358 if (_fieldAccessNeverThrows(field)) return false; |
| 355 return backend.shouldRetainGetter(field) | 359 return backend.shouldRetainGetter(field) |
| 356 || _compiler.codegenWorld.hasInvokedGetter(field, _compiler.world); | 360 || _compiler.codegenWorld.hasInvokedGetter(field, _compiler.world); |
| 357 } | 361 } |
| 358 | 362 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 if (isIntercepted) { | 399 if (isIntercepted) { |
| 396 setterFlags += 2; | 400 setterFlags += 2; |
| 397 if (backend.isInterceptorClass(holder)) { | 401 if (backend.isInterceptorClass(holder)) { |
| 398 setterFlags += 1; | 402 setterFlags += 1; |
| 399 } | 403 } |
| 400 } else { | 404 } else { |
| 401 setterFlags = 1; | 405 setterFlags = 1; |
| 402 } | 406 } |
| 403 } | 407 } |
| 404 | 408 |
| 405 return new InstanceField(name, getterFlags, setterFlags); | 409 return new InstanceField(field, name, getterFlags, setterFlags); |
| 406 } | 410 } |
| 407 | 411 |
| 408 Iterable<StaticMethod> _generateOneShotInterceptors() { | 412 Iterable<StaticMethod> _generateOneShotInterceptors() { |
| 409 emitterTask.InterceptorStubGenerator stubGenerator = | 413 emitterTask.InterceptorStubGenerator stubGenerator = |
| 410 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); | 414 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend); |
| 411 | 415 |
| 412 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 416 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 413 Holder holder = _registry.registerHolder(holderName); | 417 Holder holder = _registry.registerHolder(holderName); |
| 414 | 418 |
| 415 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); | 419 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); |
| 416 return names.map((String name) { | 420 return names.map((String name) { |
| 417 js.Expression code = stubGenerator.generateOneShotInterceptor(name); | 421 js.Expression code = stubGenerator.generateOneShotInterceptor(name); |
| 418 return new StaticMethod(name, holder, code); | 422 return new StaticStubMethod(name, holder, code); |
| 419 }); | 423 }); |
| 420 } | 424 } |
| 421 | 425 |
| 422 StaticMethod _buildStaticMethod(FunctionElement element) { | 426 StaticMethod _buildStaticMethod(FunctionElement element) { |
| 423 String name = namer.getNameOfMember(element); | 427 String name = namer.getNameOfMember(element); |
| 424 String holder = namer.globalObjectFor(element); | 428 String holder = namer.globalObjectFor(element); |
| 425 js.Expression code = backend.generatedCode[element]; | 429 js.Expression code = backend.generatedCode[element]; |
| 426 return new StaticMethod(name, _registry.registerHolder(holder), code); | 430 return new StaticMethod(element, |
| 431 name, _registry.registerHolder(holder), code); |
| 427 } | 432 } |
| 428 | 433 |
| 429 StaticMethod _buildStaticMethodTearOff(FunctionElement element) { | 434 StaticMethod _buildStaticMethodTearOff(FunctionElement element) { |
| 430 String name = namer.getStaticClosureName(element); | 435 String name = namer.getStaticClosureName(element); |
| 431 String holder = namer.globalObjectFor(element); | 436 String holder = namer.globalObjectFor(element); |
| 432 // TODO(kasperl): This clearly doesn't work yet. | 437 // TODO(kasperl): This clearly doesn't work yet. |
| 433 js.Expression code = js.string("<<unimplemented>>"); | 438 js.Expression code = js.string("<<unimplemented>>"); |
| 434 return new StaticMethod(name, _registry.registerHolder(holder), code); | 439 return new StaticMethod(element, |
| 440 name, _registry.registerHolder(holder), code); |
| 435 } | 441 } |
| 436 | 442 |
| 437 void _registerConstants(OutputUnit outputUnit, | 443 void _registerConstants(OutputUnit outputUnit, |
| 438 List<ConstantValue> constantValues) { | 444 List<ConstantValue> constantValues) { |
| 439 if (constantValues == null) return; | 445 if (constantValues == null) return; |
| 440 for (ConstantValue constantValue in constantValues) { | 446 for (ConstantValue constantValue in constantValues) { |
| 441 assert(!_constants.containsKey(constantValue)); | 447 assert(!_constants.containsKey(constantValue)); |
| 442 String name = namer.constantName(constantValue); | 448 String name = namer.constantName(constantValue); |
| 443 String constantObject = namer.globalObjectForConstant(constantValue); | 449 String constantObject = namer.globalObjectForConstant(constantValue); |
| 444 Holder holder = _registry.registerHolder(constantObject); | 450 Holder holder = _registry.registerHolder(constantObject); |
| 445 Constant constant = new Constant(name, holder, constantValue); | 451 Constant constant = new Constant(name, holder, constantValue); |
| 446 _constants[constantValue] = constant; | 452 _constants[constantValue] = constant; |
| 447 }; | 453 }; |
| 448 } | 454 } |
| 449 } | 455 } |
| OLD | NEW |