Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart

Issue 895083002: Support tearoffs in the new emitter. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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.new_js_emitter.model_emitter; 5 library dart2js.new_js_emitter.model_emitter;
6 6
7 import '../../dart2jslib.dart' show Compiler; 7 import '../../dart2jslib.dart' show Compiler;
8 import '../../dart_types.dart' show DartType;
8 import '../../js/js.dart' as js; 9 import '../../js/js.dart' as js;
9 import '../../js_backend/js_backend.dart' show 10 import '../../js_backend/js_backend.dart' show
10 JavaScriptBackend, 11 JavaScriptBackend,
11 Namer, 12 Namer,
12 ConstantEmitter; 13 ConstantEmitter;
13 14
14 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show 15 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show
15 DEFERRED_LIBRARY_URIS, 16 DEFERRED_LIBRARY_URIS,
16 DEFERRED_LIBRARY_HASHES, 17 DEFERRED_LIBRARY_HASHES,
17 GET_TYPE_FROM_NAME, 18 GET_TYPE_FROM_NAME,
18 INITIALIZE_LOADED_HUNK, 19 INITIALIZE_LOADED_HUNK,
19 IS_HUNK_INITIALIZED, 20 IS_HUNK_INITIALIZED,
20 IS_HUNK_LOADED, 21 IS_HUNK_LOADED,
21 MANGLED_GLOBAL_NAMES, 22 MANGLED_GLOBAL_NAMES,
22 METADATA, 23 METADATA,
23 TYPE_TO_INTERCEPTOR_MAP; 24 TYPE_TO_INTERCEPTOR_MAP;
24 25
25 import '../js_emitter.dart' show NativeGenerator; 26 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode;
26 import '../model.dart'; 27 import '../model.dart';
27 28
29
28 class ModelEmitter { 30 class ModelEmitter {
29 final Compiler compiler; 31 final Compiler compiler;
30 final Namer namer; 32 final Namer namer;
31 final ConstantEmitter constantEmitter; 33 final ConstantEmitter constantEmitter;
32 34
33 JavaScriptBackend get backend => compiler.backend; 35 JavaScriptBackend get backend => compiler.backend;
34 36
35 /// For deferred loading we communicate the initializers via this global var. 37 /// For deferred loading we communicate the initializers via this global var.
36 static const String deferredInitializersGlobal = 38 static const String deferredInitializersGlobal =
37 r"$__dart_deferred_initializers__"; 39 r"$__dart_deferred_initializers__";
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 } else { 103 } else {
102 nativeBoilerplate = js.js.statement(";"); 104 nativeBoilerplate = js.js.statement(";");
103 } 105 }
104 106
105 js.Expression code = new js.ArrayInitializer(elements); 107 js.Expression code = new js.ArrayInitializer(elements);
106 108
107 return js.js.statement( 109 return js.js.statement(
108 boilerplate, 110 boilerplate,
109 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), 111 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap),
110 'holders': emitHolders(fragment.holders), 112 'holders': emitHolders(fragment.holders),
113 'tearOff': buildTearOffCode(backend),
114 'parseFunctionDescriptor':
115 js.js.statement(parseFunctionDescriptorBoilerplate),
111 'cyclicThrow': 116 'cyclicThrow':
112 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), 117 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()),
113 'outputContainsConstantList': program.outputContainsConstantList, 118 'outputContainsConstantList': program.outputContainsConstantList,
114 'embeddedGlobals': emitEmbeddedGlobals(program), 119 'embeddedGlobals': emitEmbeddedGlobals(program),
115 'constants': emitConstants(fragment.constants), 120 'constants': emitConstants(fragment.constants),
116 'staticNonFinals': 121 'staticNonFinals':
117 emitStaticNonFinalFields(fragment.staticNonFinalFields), 122 emitStaticNonFinalFields(fragment.staticNonFinalFields),
118 'nativeBoilerplate': nativeBoilerplate, 123 'nativeBoilerplate': nativeBoilerplate,
119 'operatorIsPrefix': js.string(namer.operatorIsPrefix), 124 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
120 'eagerClasses': emitEagerClassInitializations(fragment.libraries), 125 'eagerClasses': emitEagerClassInitializations(fragment.libraries),
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 List elements = [js.string(cls.superclassName), 393 List elements = [js.string(cls.superclassName),
389 js.number(cls.superclassHolderIndex)]; 394 js.number(cls.superclassHolderIndex)];
390 395
391 if (cls.isMixinApplication) { 396 if (cls.isMixinApplication) {
392 MixinApplication mixin = cls; 397 MixinApplication mixin = cls;
393 elements.add(js.string(mixin.mixinClass.name)); 398 elements.add(js.string(mixin.mixinClass.name));
394 elements.add(js.number(mixin.mixinClass.holder.index)); 399 elements.add(js.number(mixin.mixinClass.holder.index));
395 } else { 400 } else {
396 elements.add(_generateConstructor(cls)); 401 elements.add(_generateConstructor(cls));
397 } 402 }
398 Iterable<Method> methods = cls.methods.expand((Method method) { 403 Iterable<Method> methods = cls.methods;
399 // TODO(floitsch): can there be anything else than a DartMethod?
400 if (method is DartMethod) {
401 return [method]..addAll(method.parameterStubs);
402 } else {
403 return [method];
404 }
405 });
406 Iterable<Method> isChecks = cls.isChecks; 404 Iterable<Method> isChecks = cls.isChecks;
407 Iterable<Method> callStubs = cls.callStubs; 405 Iterable<Method> callStubs = cls.callStubs;
408 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; 406 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs;
409 Iterable<Method> gettersSetters = _generateGettersSetters(cls); 407 Iterable<Method> gettersSetters = _generateGettersSetters(cls);
410 Iterable<Method> allMethods = 408 Iterable<Method> allMethods =
411 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters] 409 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters]
412 .expand((x) => x); 410 .expand((x) => x);
413 elements.addAll(allMethods.expand((e) => [js.string(e.name), e.code])); 411 elements.addAll(allMethods.expand(emitInstanceMethod));
412
414 return unparse(compiler, new js.ArrayInitializer(elements)); 413 return unparse(compiler, new js.ArrayInitializer(elements));
415 } 414 }
416 415
417 js.Expression emitLazyInitializer(StaticField field) { 416 js.Expression emitLazyInitializer(StaticField field) {
418 assert(field.isLazy); 417 assert(field.isLazy);
419 return unparse(compiler, field.code); 418 return unparse(compiler, field.code);
420 } 419 }
421 420
421 /// JavaScript code template that implements parsing of a function descriptor.
422 /// Descriptors are used in place of the actual JavaScript function
423 /// definition in the output if additional information needs to be passed to
424 /// facilitate the generation of tearOffs at runtime. The format is an array
425 /// with the following fields:
426 ///
427 /// [Method.code]
428 /// [DartMethod.callName]
429 /// [DartMethod.tearOffName]
430 /// [JavaScriptBackend.isInterceptedMethod]
431 /// functionType
432 ///
433 /// followed by
434 ///
435 /// [ParameterStubMethod.name]
436 /// [ParameterStubMethod.code]
437 ///
438 /// for each stub in [DartMethod.parameterStubs].
439
440 static final String parseFunctionDescriptorBoilerplate = r"""
441 function parseFunctionDescriptor(proto, name, descriptor) {
442 if (descriptor instanceof Array) {
443 proto[name] = descriptor[0];
444 var funs = [descriptor[0]];
445 funs[0].$callName = descriptor[1];
446 for (var pos = 5; pos < descriptor.length; pos += 3) {
447 var stub = descriptor[pos+2];
floitsch 2015/02/03 19:40:02 nit: "pos + 2" (and "pos + 1" in the next line).
herhut 2015/02/03 21:18:58 Done.
448 stub.$callName = descriptor[pos+1];
449 proto[descriptor[pos]] = stub;
450 funs.push(stub);
451 }
452 if (descriptor[2] != null) {
453 var isIntercepted = descriptor[3];
454 var reflectionInfo = descriptor[4];
455 proto[descriptor[2]] =
456 tearOff(funs, reflectionInfo, false, name, isIntercepted);
457 }
458 } else {
459 proto[name] = descriptor;
460 }
461 }
462 """;
463
464 js.Expression _generateFunctionType(DartType memberType) {
465 if (memberType.containsTypeVariables) {
466 js.Expression thisAccess = js.js(r'this.$receiver');
467 return backend.rti.getSignatureEncoding(memberType, thisAccess);
468 } else {
469 return js.number(backend.emitter.metadataCollector.reifyType(memberType));
470 }
471 }
472
473 Iterable<js.Expression> emitInstanceMethod(Method method) {
474
475 List<js.Expression> makeNameCodePair(Method method) {
476 return [js.string(method.name), method.code];
477 }
478
479 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) {
480 js.Expression callName = stub.callName == null
481 ? new js.LiteralNull()
482 : js.string(stub.callName);
483 return [js.string(stub.name), callName, stub.code];
484 }
485
486 if (method is DartMethod) {
487 if (method.needsTearOff) {
488 /// See [parseFunctionDescriptorBoilerplate] for a full description of
489 /// the format.
490 // [name, [function, callName, tearOffName, isIntercepted, functionType,
491 // stub1_name, stub1_callName, stub1_code, ...]
492 bool isIntercepted = backend.isInterceptedMethod(method.element);
493 var data = [method.code];
494 data.add(js.string(method.callName));
495 data.add(js.string(method.tearOffName));
496 data.add(new js.LiteralBool(isIntercepted));
497 data.add(_generateFunctionType(method.type));
498 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
499 return [js.string(method.name), new js.ArrayInitializer(data)];
500 } else {
501 // TODO(floitsch): not the most efficient way...
502 return ([method]..addAll(method.parameterStubs))
503 .expand(makeNameCodePair);
504 }
505 } else {
506 return makeNameCodePair(method);
507 }
508 }
509
422 Iterable<js.Expression> emitStaticMethod(StaticMethod method) { 510 Iterable<js.Expression> emitStaticMethod(StaticMethod method) {
423 js.Expression holderIndex = js.number(method.holder.index); 511 js.Expression holderIndex = js.number(method.holder.index);
424 List<js.Expression> output = <js.Expression>[]; 512 List<js.Expression> output = <js.Expression>[];
425 513
426 void _addMethod(Method method) { 514 void _addMethod(Method method) {
427 js.Expression unparsed = unparse(compiler, method.code); 515 js.Expression unparsed = unparse(compiler, method.code);
428 output.add(js.string(method.name)); 516 output.add(js.string(method.name));
429 output.add(holderIndex); 517 output.add(holderIndex);
430 output.add(unparsed); 518 output.add(unparsed);
431 } 519 }
432 520
521 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) {
522 js.Expression callName = stub.callName == null
523 ? new js.LiteralNull()
524 : js.string(stub.callName);
525 return [js.string(stub.name), callName, unparse(compiler, stub.code)];
526 }
527
433 _addMethod(method); 528 _addMethod(method);
434 // TODO(floitsch): can there be anything else than a StaticDartMethod? 529 // TODO(floitsch): can there be anything else than a StaticDartMethod?
floitsch 2015/02/03 19:40:02 Well now there can be, since you run it over every
herhut 2015/02/03 21:18:58 Doesn't this still only run over static methods?
floitsch 2015/02/03 21:44:17 Never mind...
435 if (method is StaticDartMethod) { 530 if (method is StaticDartMethod) {
436 method.parameterStubs.forEach(_addMethod); 531 if (method.needsTearOff) {
532 /// The format emitted is the same as for the parser specified at
533 /// [parseFunctionDescriptorBoilerplate] except for the missing
534 /// field whether the method is intercepted.
535 // [name, [function, callName, tearOffName, functionType,
536 // stub1_name, stub1_callName, stub1_code, ...]
537 var data = [unparse(compiler, method.code)];
538 data.add(js.string(method.callName));
539 data.add(js.string(method.tearOffName));
540 data.add(_generateFunctionType(method.type));
541 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
542 return [js.string(method.name), holderIndex, new js.ArrayInitializer(dat a)];
floitsch 2015/02/03 19:40:02 long line.
herhut 2015/02/03 21:18:58 Done.
543 } else {
544 method.parameterStubs.forEach(_addMethod);
545 }
437 } 546 }
438 return output; 547 return output;
439 } 548 }
440 549
441 static final String boilerplate = """ 550 static final String boilerplate = """
442 { 551 {
443 // Declare deferred-initializer global. 552 // Declare deferred-initializer global.
444 #deferredInitializer; 553 #deferredInitializer;
445 554
446 !function(start, program) { 555 !function(start, program) {
447
448 // Initialize holder objects. 556 // Initialize holder objects.
449 #holders; 557 #holders;
450 558
559 // Counter to generate unique names for tear offs.
560 var functionCounter = 0;
floitsch 2015/02/03 19:40:02 :/ Can this be emitted with the tear-off function?
herhut 2015/02/03 21:18:58 In a separate CL to do it for both emitters.
floitsch 2015/02/03 21:44:17 Acknowledged.
561
451 function setupProgram() { 562 function setupProgram() {
452 for (var i = 0; i < program.length - 1; i++) { 563 for (var i = 0; i < program.length - 1; i++) {
453 setupLibrary(program[i]); 564 setupLibrary(program[i]);
454 } 565 }
455 setupLazyStatics(program[i]); 566 setupLazyStatics(program[i]);
456 } 567 }
457 568
458 function setupLibrary(library) { 569 function setupLibrary(library) {
459 var statics = library[0]; 570 var statics = library[0];
460 for (var i = 0; i < statics.length; i += 3) { 571 for (var i = 0; i < statics.length; i += 3) {
(...skipping 13 matching lines...) Expand all
474 for (var i = 0; i < statics.length; i += 4) { 585 for (var i = 0; i < statics.length; i += 4) {
475 var name = statics[i]; 586 var name = statics[i];
476 var getterName = statics[i + 1]; 587 var getterName = statics[i + 1];
477 var holderIndex = statics[i + 2]; 588 var holderIndex = statics[i + 2];
478 var initializer = statics[i + 3]; 589 var initializer = statics[i + 3];
479 setupLazyStatic(name, getterName, holders[holderIndex], initializer); 590 setupLazyStatic(name, getterName, holders[holderIndex], initializer);
480 } 591 }
481 } 592 }
482 593
483 function setupStatic(name, holder, descriptor) { 594 function setupStatic(name, holder, descriptor) {
484 holder[name] = function() { 595 if (typeof descriptor == 'string') {
485 var method = compile(name, descriptor); 596 holder[name] = function() {
486 holder[name] = method; 597 var method = compile(name, descriptor);
487 return method.apply(this, arguments); 598 holder[name] = method;
488 }; 599 return method.apply(this, arguments);
600 };
601 } else {
602 // Parse the tear off information and generate compile handlers.
603 // TODO(herhut): Share parser with instance methods.
floitsch 2015/02/03 19:40:02 I'm not sure that's worth the effort, but I agree
herhut 2015/02/03 21:18:58 Acknowledged.
604 function compileAllStubs() {
605 var funs;
606 var fun = compile(name, descriptor[0]);
607 fun.\$callName = descriptor[1];
608 holder[name] = fun;
609 funs = [fun];
610 for (var pos = 4; pos < descriptor.length; pos += 3) {
611 var stubName = descriptor[pos];
612 fun = compile(stubName, descriptor[pos + 2]);
613 fun.\$callName = descriptor[pos + 1];
614 holder[stubName] = fun;
615 funs.push(fun);
616 }
617 if (descriptor[2] != null) { // tear-off name.
618 // functions, reflectionInfo, isStatic, name, isIntercepted.
619 holder[descriptor[2]] =
620 tearOff(funs, descriptor[3], true, name, false);
621 }
622 }
623
624 function setupCompileAllAndDelegateStub(name) {
625 holder[name] = function() {
626 compileAllStubs();
627 return holder[name].apply(this, arguments);
628 };
629 }
630
631 setupCompileAllAndDelegateStub(name);
632 for (var pos = 4; pos < descriptor.length; pos += 3) {
633 setupCompileAllAndDelegateStub(descriptor[pos]);
634 }
635 if (descriptor[2] != null) { // tear-off name.
636 setupCompileAllAndDelegateStub(descriptor[2])
637 }
638 }
489 } 639 }
490 640
491 function setupLazyStatic(name, getterName, holder, descriptor) { 641 function setupLazyStatic(name, getterName, holder, descriptor) {
492 holder[name] = null; 642 holder[name] = null;
493 holder[getterName] = function() { 643 holder[getterName] = function() {
494 var initializer = compile(name, descriptor); 644 var initializer = compile(name, descriptor);
495 holder[getterName] = function() { #cyclicThrow(name) }; 645 holder[getterName] = function() { #cyclicThrow(name) };
496 var result; 646 var result;
497 var sentinelInProgress = descriptor; 647 var sentinelInProgress = descriptor;
498 try { 648 try {
(...skipping 27 matching lines...) Expand all
526 constructor.apply(object, arguments); 676 constructor.apply(object, arguments);
527 return object; 677 return object;
528 }; 678 };
529 679
530 // We store the ensureResolved function on the patch function to make it 680 // We store the ensureResolved function on the patch function to make it
531 // possible to resolve superclass references without constructing instances. 681 // possible to resolve superclass references without constructing instances.
532 patch.ensureResolved = ensureResolved; 682 patch.ensureResolved = ensureResolved;
533 holder[name] = patch; 683 holder[name] = patch;
534 } 684 }
535 685
686 #tearOff;
687
688 #parseFunctionDescriptor;
689
536 function compileConstructor(name, descriptor) { 690 function compileConstructor(name, descriptor) {
537 descriptor = compile(name, descriptor); 691 descriptor = compile(name, descriptor);
538 var prototype = determinePrototype(descriptor); 692 var prototype = determinePrototype(descriptor);
539 var constructor; 693 var constructor;
540 // $mixinFormatDescription. 694 // $mixinFormatDescription.
541 if (typeof descriptor[2] !== 'function') { 695 if (typeof descriptor[2] !== 'function') {
542 constructor = compileMixinConstructor(name, prototype, descriptor); 696 constructor = compileMixinConstructor(name, prototype, descriptor);
543 for (var i = 4; i < descriptor.length; i += 2) { 697 for (var i = 4; i < descriptor.length; i += 2) {
544 prototype[descriptor[i]] = descriptor[i + 1]; 698 parseFunctionDescriptor(prototype, descriptor, descriptor[i + 1]);
545 } 699 }
546 } else { 700 } else {
547 constructor = descriptor[2]; 701 constructor = descriptor[2];
548 for (var i = 3; i < descriptor.length; i += 2) { 702 for (var i = 3; i < descriptor.length; i += 2) {
549 prototype[descriptor[i]] = descriptor[i + 1]; 703 parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
550 } 704 }
551 } 705 }
552 constructor.builtin\$cls = name; // Needed for RTI. 706 constructor.builtin\$cls = name; // Needed for RTI.
553 constructor.prototype = prototype; 707 constructor.prototype = prototype;
554 prototype[#operatorIsPrefix + name] = constructor; 708 prototype[#operatorIsPrefix + name] = constructor;
555 prototype.constructor = constructor; 709 prototype.constructor = constructor;
556 return constructor; 710 return constructor;
557 } 711 }
558 712
559 function compileMixinConstructor(name, prototype, descriptor) { 713 function compileMixinConstructor(name, prototype, descriptor) {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 780
627 var end = Date.now(); 781 var end = Date.now();
628 print('Setup: ' + (end - start) + ' ms.'); 782 print('Setup: ' + (end - start) + ' ms.');
629 783
630 #main(); // Start main. 784 #main(); // Start main.
631 785
632 }(Date.now(), #code) 786 }(Date.now(), #code)
633 }"""; 787 }""";
634 788
635 } 789 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698