| 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 248 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 /// HACK for Try. | 265 /// HACK for Try. |
| 266 /// | 266 /// |
| 267 /// Returns a class that contains the fields of a class. | 267 /// Returns a class that contains the fields of a class. |
| 268 Class buildClassWithFieldsForTry(ClassElement element) { | 268 Class buildClassWithFieldsForTry(ClassElement element) { |
| 269 assert(_compiler.hasIncrementalSupport); |
| 269 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); | 270 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element); |
| 270 | 271 |
| 271 List<Field> instanceFields = | 272 List<Field> instanceFields = |
| 272 onlyForRti ? const <Field>[] : _buildFields(element, false); | 273 onlyForRti ? const <Field>[] : _buildFields(element, false); |
| 273 | 274 |
| 274 String name = namer.getNameOfClass(element); | 275 String name = namer.getNameOfClass(element); |
| 275 String holderName = namer.globalObjectFor(element); | 276 String holderName = namer.globalObjectFor(element); |
| 276 Holder holder = _registry.registerHolder(holderName); | 277 Holder holder = _registry.registerHolder(holderName); |
| 277 bool isInstantiated = | 278 bool isInstantiated = |
| 278 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 279 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 289 | 290 |
| 290 List<Method> methods = []; | 291 List<Method> methods = []; |
| 291 List<StubMethod> callStubs = <StubMethod>[]; | 292 List<StubMethod> callStubs = <StubMethod>[]; |
| 292 | 293 |
| 293 void visitMember(ClassElement enclosing, Element member) { | 294 void visitMember(ClassElement enclosing, Element member) { |
| 294 assert(invariant(element, member.isDeclaration)); | 295 assert(invariant(element, member.isDeclaration)); |
| 295 assert(invariant(element, element == enclosing)); | 296 assert(invariant(element, element == enclosing)); |
| 296 | 297 |
| 297 if (Elements.isNonAbstractInstanceMember(member)) { | 298 if (Elements.isNonAbstractInstanceMember(member)) { |
| 298 js.Expression code = backend.generatedCode[member]; | 299 js.Expression code = backend.generatedCode[member]; |
| 299 // TODO(kasperl): Figure out under which conditions code is null. | 300 // TODO(herhut): Remove once _buildMethod can no longer return null. |
| 300 if (code != null) methods.add(_buildMethod(member, code)); | 301 Method method = _buildMethod(member); |
| 302 if (method != null) methods.add(method); |
| 301 } | 303 } |
| 302 if (member.isGetter || member.isField) { | 304 if (member.isGetter || member.isField) { |
| 303 Set<Selector> selectors = | 305 Set<Selector> selectors = |
| 304 _compiler.codegenWorld.invokedNames[member.name]; | 306 _compiler.codegenWorld.invokedNames[member.name]; |
| 305 if (selectors != null && !selectors.isEmpty) { | 307 if (selectors != null && !selectors.isEmpty) { |
| 306 ClassStubGenerator generator = | 308 ClassStubGenerator generator = |
| 307 new ClassStubGenerator(_compiler, namer, backend); | 309 new ClassStubGenerator(_compiler, namer, backend); |
| 308 Map<String, js.Expression> callStubsForMember = | 310 Map<String, js.Expression> callStubsForMember = |
| 309 generator.generateCallStubsForGetter(member, selectors); | 311 generator.generateCallStubsForGetter(member, selectors); |
| 310 callStubsForMember.forEach((String name, js.Expression code) { | 312 callStubsForMember.forEach((String name, js.Expression code) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 isChecks, | 369 isChecks, |
| 368 typeTests.functionTypeIndex, | 370 typeTests.functionTypeIndex, |
| 369 isDirectlyInstantiated: isInstantiated, | 371 isDirectlyInstantiated: isInstantiated, |
| 370 onlyForRti: onlyForRti, | 372 onlyForRti: onlyForRti, |
| 371 isNative: element.isNative); | 373 isNative: element.isNative); |
| 372 } | 374 } |
| 373 _classes[element] = result; | 375 _classes[element] = result; |
| 374 return result; | 376 return result; |
| 375 } | 377 } |
| 376 | 378 |
| 377 Method _buildMethod(FunctionElement element, js.Expression code) { | 379 bool _methodNeedsStubs(FunctionElement method) { |
| 380 return !method.functionSignature.optionalParameters.isEmpty; |
| 381 } |
| 382 |
| 383 bool _methodCanBeReflected(FunctionElement method) { |
| 384 return backend.isAccessibleByReflection(method) || |
| 385 // During incremental compilation, we have to assume that reflection |
| 386 // *might* get enabled. |
| 387 _compiler.hasIncrementalSupport; |
| 388 } |
| 389 |
| 390 bool _methodCanBeApplied(FunctionElement method) { |
| 391 return _compiler.enabledFunctionApply && |
| 392 _compiler.world.getMightBePassedToApply(method); |
| 393 } |
| 394 |
| 395 // TODO(herhut): Refactor incremental compilation and remove method. |
| 396 Method buildMethodHackForIncrementalCompilation(FunctionElement element) { |
| 397 assert(_compiler.hasIncrementalSupport); |
| 398 if (element.isInstanceMember) { |
| 399 return _buildMethod(element); |
| 400 } else { |
| 401 return _buildStaticMethod(element); |
| 402 } |
| 403 } |
| 404 |
| 405 DartMethod _buildMethod(FunctionElement element) { |
| 378 String name = namer.getNameOfInstanceMember(element); | 406 String name = namer.getNameOfInstanceMember(element); |
| 379 // TODO(floitsch): compute `needsTearOff`. | 407 js.Expression code = backend.generatedCode[element]; |
| 380 return new Method(element, name, code, needsTearOff: false); | 408 |
| 409 // TODO(kasperl): Figure out under which conditions code is null. |
| 410 if (code == null) return null; |
| 411 |
| 412 bool canTearOff = false; |
| 413 String tearOffName; |
| 414 bool isClosure = false; |
| 415 bool isNotApplyTarget = !element.isFunction || element.isAccessor; |
| 416 |
| 417 final bool needsStubs = _methodNeedsStubs(element); |
| 418 final bool canBeReflected = _methodCanBeReflected(element); |
| 419 final bool canBeApplied = _methodCanBeApplied(element); |
| 420 final bool hasSuperAlias = backend.isAliasedSuperMember(element); |
| 421 |
| 422 if (isNotApplyTarget) { |
| 423 canTearOff = false; |
| 424 } else { |
| 425 if (element.enclosingClass.isClosure) { |
| 426 canTearOff = false; |
| 427 isClosure = true; |
| 428 } else { |
| 429 // Careful with operators. |
| 430 canTearOff = universe.hasInvokedGetter(element, _compiler.world) || |
| 431 (canBeReflected && !element.isOperator); |
| 432 assert(canTearOff || |
| 433 !universe.methodsNeedingSuperGetter.contains(element)); |
| 434 tearOffName = namer.getterName(element); |
| 435 } |
| 436 } |
| 437 |
| 438 if (canTearOff) { |
| 439 assert(invariant(element, !element.isGenerativeConstructor)); |
| 440 assert(invariant(element, !element.isGenerativeConstructorBody)); |
| 441 assert(invariant(element, !element.isConstructor)); |
| 442 } |
| 443 |
| 444 return new InstanceMethod(element, name, code, needsTearOff: canTearOff, |
| 445 tearOffName: tearOffName, isClosure: isClosure, |
| 446 hasSuperAlias: hasSuperAlias, canBeApplied: canBeApplied, |
| 447 canBeReflected: canBeReflected, needsStubs: needsStubs); |
| 381 } | 448 } |
| 382 | 449 |
| 383 /// Builds a stub method. | 450 /// Builds a stub method. |
| 384 /// | 451 /// |
| 385 /// Stub methods may have an element that can be used for code-size | 452 /// Stub methods may have an element that can be used for code-size |
| 386 /// attribution. | 453 /// attribution. |
| 387 Method _buildStubMethod(String name, js.Expression code, | 454 Method _buildStubMethod(String name, js.Expression code, |
| 388 {Element element}) { | 455 {Element element}) { |
| 389 // TODO(floitsch): compute `needsTearOff`. | 456 return new StubMethod(name, code, element: element); |
| 390 return new StubMethod(name, code, needsTearOff: false, element: element); | |
| 391 } | 457 } |
| 392 | 458 |
| 393 // The getInterceptor methods directly access the prototype of classes. | 459 // The getInterceptor methods directly access the prototype of classes. |
| 394 // We must evaluate these classes eagerly so that the prototype is | 460 // We must evaluate these classes eagerly so that the prototype is |
| 395 // accessible. | 461 // accessible. |
| 396 void _markEagerInterceptorClasses() { | 462 void _markEagerInterceptorClasses() { |
| 397 Map<String, Set<ClassElement>> specializedGetInterceptors = | 463 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 398 backend.specializedGetInterceptors; | 464 backend.specializedGetInterceptors; |
| 399 for (Set<ClassElement> classes in specializedGetInterceptors.values) { | 465 for (Set<ClassElement> classes in specializedGetInterceptors.values) { |
| 400 for (ClassElement element in classes) { | 466 for (ClassElement element in classes) { |
| 401 Class cls = _classes[element]; | 467 Class cls = _classes[element]; |
| 402 if (cls != null) cls.isEager = true; | 468 if (cls != null) cls.isEager = true; |
| 403 } | 469 } |
| 404 } | 470 } |
| 405 } | 471 } |
| 406 | 472 |
| 407 Iterable<StaticMethod> _generateGetInterceptorMethods() { | 473 Iterable<StaticMethod> _generateGetInterceptorMethods() { |
| 408 InterceptorStubGenerator stubGenerator = | 474 InterceptorStubGenerator stubGenerator = |
| 409 new InterceptorStubGenerator(_compiler, namer, backend); | 475 new InterceptorStubGenerator(_compiler, namer, backend); |
| 410 | 476 |
| 411 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 477 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 412 Holder holder = _registry.registerHolder(holderName); | 478 Holder holder = _registry.registerHolder(holderName); |
| 413 | 479 |
| 414 Map<String, Set<ClassElement>> specializedGetInterceptors = | 480 Map<String, Set<ClassElement>> specializedGetInterceptors = |
| 415 backend.specializedGetInterceptors; | 481 backend.specializedGetInterceptors; |
| 416 List<String> names = specializedGetInterceptors.keys.toList()..sort(); | 482 List<String> names = specializedGetInterceptors.keys.toList()..sort(); |
| 417 return names.map((String name) { | 483 return names.map((String name) { |
| 418 Set<ClassElement> classes = specializedGetInterceptors[name]; | 484 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 419 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 485 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| 420 // TODO(floitsch): compute `needsTearOff`. | 486 return new StaticStubMethod(name, holder, code); |
| 421 return new StaticStubMethod(name, holder, code, needsTearOff: false); | |
| 422 }); | 487 }); |
| 423 } | 488 } |
| 424 | 489 |
| 425 List<Field> _buildFields(Element holder, bool visitStatics) { | 490 List<Field> _buildFields(Element holder, bool visitStatics) { |
| 426 List<Field> fields = <Field>[]; | 491 List<Field> fields = <Field>[]; |
| 427 _task.oldEmitter.classEmitter.visitFields( | 492 _task.oldEmitter.classEmitter.visitFields( |
| 428 holder, visitStatics, (VariableElement field, | 493 holder, visitStatics, (VariableElement field, |
| 429 String name, | 494 String name, |
| 430 String accessorName, | 495 String accessorName, |
| 431 bool needsGetter, | 496 bool needsGetter, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 Iterable<StaticMethod> _generateOneShotInterceptors() { | 536 Iterable<StaticMethod> _generateOneShotInterceptors() { |
| 472 InterceptorStubGenerator stubGenerator = | 537 InterceptorStubGenerator stubGenerator = |
| 473 new InterceptorStubGenerator(_compiler, namer, backend); | 538 new InterceptorStubGenerator(_compiler, namer, backend); |
| 474 | 539 |
| 475 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); | 540 String holderName = namer.globalObjectFor(backend.interceptorsLibrary); |
| 476 Holder holder = _registry.registerHolder(holderName); | 541 Holder holder = _registry.registerHolder(holderName); |
| 477 | 542 |
| 478 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); | 543 List<String> names = backend.oneShotInterceptors.keys.toList()..sort(); |
| 479 return names.map((String name) { | 544 return names.map((String name) { |
| 480 js.Expression code = stubGenerator.generateOneShotInterceptor(name); | 545 js.Expression code = stubGenerator.generateOneShotInterceptor(name); |
| 481 return new StaticStubMethod(name, holder, code, needsTearOff: false); | 546 return new StaticStubMethod(name, holder, code); |
| 482 }); | 547 }); |
| 483 } | 548 } |
| 484 | 549 |
| 485 StaticMethod _buildStaticMethod(FunctionElement element) { | 550 StaticMethod _buildStaticMethod(FunctionElement element) { |
| 486 String name = namer.getNameOfMember(element); | 551 String name = namer.getNameOfMember(element); |
| 487 String holder = namer.globalObjectFor(element); | 552 String holder = namer.globalObjectFor(element); |
| 488 js.Expression code = backend.generatedCode[element]; | 553 js.Expression code = backend.generatedCode[element]; |
| 489 bool needsTearOff = | 554 |
| 490 universe.staticFunctionsNeedingGetter.contains(element); | 555 final bool isNotApplyTarget = !element.isConstructor && !element.isAccessor; |
| 491 // TODO(floitsch): add tear-off name: namer.getStaticClosureName(element). | 556 final bool needsStubs = _methodNeedsStubs(element); |
| 557 final bool canBeApplied = _methodCanBeApplied(element); |
| 558 final bool canBeReflected = _methodCanBeReflected(element); |
| 559 |
| 560 final bool needsTearOff = isNotApplyTarget && (canBeReflected || |
| 561 universe.staticFunctionsNeedingGetter.contains(element)); |
| 562 |
| 563 final String tearOffName = |
| 564 needsTearOff ? namer.getStaticClosureName(element) : null; |
| 565 |
| 492 return new StaticMethod(element, | 566 return new StaticMethod(element, |
| 493 name, _registry.registerHolder(holder), code, | 567 name, _registry.registerHolder(holder), code, |
| 494 needsTearOff: needsTearOff); | 568 needsTearOff: needsTearOff, |
| 569 tearOffName: tearOffName, |
| 570 canBeApplied: canBeApplied, |
| 571 canBeReflected: canBeReflected, |
| 572 needsStubs: needsStubs); |
| 495 } | 573 } |
| 496 | 574 |
| 497 void _registerConstants(OutputUnit outputUnit, | 575 void _registerConstants(OutputUnit outputUnit, |
| 498 Iterable<ConstantValue> constantValues) { | 576 Iterable<ConstantValue> constantValues) { |
| 499 // `constantValues` is null if an outputUnit doesn't contain any constants. | 577 // `constantValues` is null if an outputUnit doesn't contain any constants. |
| 500 if (constantValues == null) return; | 578 if (constantValues == null) return; |
| 501 for (ConstantValue constantValue in constantValues) { | 579 for (ConstantValue constantValue in constantValues) { |
| 502 _registry.registerConstant(outputUnit, constantValue); | 580 _registry.registerConstant(outputUnit, constantValue); |
| 503 assert(!_constants.containsKey(constantValue)); | 581 assert(!_constants.containsKey(constantValue)); |
| 504 String name = namer.constantName(constantValue); | 582 String name = namer.constantName(constantValue); |
| 505 String constantObject = namer.globalObjectForConstant(constantValue); | 583 String constantObject = namer.globalObjectForConstant(constantValue); |
| 506 Holder holder = _registry.registerHolder(constantObject); | 584 Holder holder = _registry.registerHolder(constantObject); |
| 507 Constant constant = new Constant(name, holder, constantValue); | 585 Constant constant = new Constant(name, holder, constantValue); |
| 508 _constants[constantValue] = constant; | 586 _constants[constantValue] = constant; |
| 509 } | 587 } |
| 510 } | 588 } |
| 511 } | 589 } |
| OLD | NEW |