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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/codegen.dart

Issue 266913017: Convert property methods into getters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 6 years, 7 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 part of ssa; 5 part of ssa;
6 6
7 class SsaCodeGeneratorTask extends CompilerTask { 7 class SsaCodeGeneratorTask extends CompilerTask {
8 8
9 final JavaScriptBackend backend; 9 final JavaScriptBackend backend;
10 10
11 SsaCodeGeneratorTask(JavaScriptBackend backend) 11 SsaCodeGeneratorTask(JavaScriptBackend backend)
12 : this.backend = backend, 12 : this.backend = backend,
13 super(backend.compiler); 13 super(backend.compiler);
14 String get name => 'SSA code generator'; 14 String get name => 'SSA code generator';
15 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; 15 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
16 16
17 17
18 js.Node attachPosition(js.Node node, Element element) { 18 js.Node attachPosition(js.Node node, Element element) {
19 // TODO(sra): Attaching positions might be cleaner if the source position 19 // TODO(sra): Attaching positions might be cleaner if the source position
20 // was on a wrapping node. 20 // was on a wrapping node.
21 SourceFile sourceFile = sourceFileOfElement(element); 21 SourceFile sourceFile = sourceFileOfElement(element);
22 ast.Node expression = element.implementation.parseNode(backend.compiler); 22 ast.Node expression = element.implementation.parseNode(backend.compiler);
23 Token beginToken; 23 Token beginToken;
24 Token endToken; 24 Token endToken;
25 if (expression == null) { 25 if (expression == null) {
26 // Synthesized node. Use the enclosing element for the location. 26 // Synthesized node. Use the enclosing element for the location.
27 beginToken = endToken = element.position(); 27 beginToken = endToken = element.position;
28 } else { 28 } else {
29 beginToken = expression.getBeginToken(); 29 beginToken = expression.getBeginToken();
30 endToken = expression.getEndToken(); 30 endToken = expression.getEndToken();
31 } 31 }
32 // TODO(podivilov): find the right sourceFile here and remove offset 32 // TODO(podivilov): find the right sourceFile here and remove offset
33 // checks below. 33 // checks below.
34 var sourcePosition, endSourcePosition; 34 var sourcePosition, endSourcePosition;
35 if (beginToken.charOffset < sourceFile.length) { 35 if (beginToken.charOffset < sourceFile.length) {
36 sourcePosition = new TokenSourceFileLocation(sourceFile, beginToken); 36 sourcePosition = new TokenSourceFileLocation(sourceFile, beginToken);
37 } 37 }
38 if (endToken.charOffset < sourceFile.length) { 38 if (endToken.charOffset < sourceFile.length) {
39 endSourcePosition = new TokenSourceFileLocation(sourceFile, endToken); 39 endSourcePosition = new TokenSourceFileLocation(sourceFile, endToken);
40 } 40 }
41 return node.withPosition(sourcePosition, endSourcePosition); 41 return node.withPosition(sourcePosition, endSourcePosition);
42 } 42 }
43 43
44 SourceFile sourceFileOfElement(Element element) { 44 SourceFile sourceFileOfElement(Element element) {
45 // TODO(johnniwinther): remove the 'element.patch' hack. 45 // TODO(johnniwinther): remove the 'element.patch' hack.
46 FunctionElement functionElement = element.asFunctionElement(); 46 FunctionElement functionElement = element.asFunctionElement();
47 if (functionElement != null && functionElement.patch != null) { 47 if (functionElement != null && functionElement.patch != null) {
48 element = functionElement.patch; 48 element = functionElement.patch;
49 } 49 }
50 return element.getCompilationUnit().script.file; 50 return element.compilationUnit.script.file;
51 } 51 }
52 52
53 js.Fun buildJavaScriptFunction(FunctionElement element, 53 js.Fun buildJavaScriptFunction(FunctionElement element,
54 List<js.Parameter> parameters, 54 List<js.Parameter> parameters,
55 js.Block body) { 55 js.Block body) {
56 return attachPosition(new js.Fun(parameters, body), element); 56 return attachPosition(new js.Fun(parameters, body), element);
57 } 57 }
58 58
59 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { 59 js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
60 if (work.element.isField()) { 60 if (work.element.isField) {
61 return generateLazyInitializer(work, graph); 61 return generateLazyInitializer(work, graph);
62 } else { 62 } else {
63 return generateMethod(work, graph); 63 return generateMethod(work, graph);
64 } 64 }
65 } 65 }
66 66
67 js.Expression generateLazyInitializer(work, graph) { 67 js.Expression generateLazyInitializer(work, graph) {
68 return measure(() { 68 return measure(() {
69 compiler.tracer.traceGraph("codegen", graph); 69 compiler.tracer.traceGraph("codegen", graph);
70 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); 70 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
(...skipping 1412 matching lines...) Expand 10 before | Expand all | Expand 10 after
1483 if (target == backend.jsArrayAdd) { 1483 if (target == backend.jsArrayAdd) {
1484 methodName = 'push'; 1484 methodName = 'push';
1485 } else if (target == backend.jsArrayRemoveLast) { 1485 } else if (target == backend.jsArrayRemoveLast) {
1486 methodName = 'pop'; 1486 methodName = 'pop';
1487 } else if (target == backend.jsStringSplit) { 1487 } else if (target == backend.jsStringSplit) {
1488 methodName = 'split'; 1488 methodName = 'split';
1489 // Split returns a List, so we make sure the backend knows the 1489 // Split returns a List, so we make sure the backend knows the
1490 // list class is instantiated. 1490 // list class is instantiated.
1491 world.registerInstantiatedClass( 1491 world.registerInstantiatedClass(
1492 compiler.listClass, work.resolutionTree); 1492 compiler.listClass, work.resolutionTree);
1493 } else if (target.isNative() && target.isFunction() 1493 } else if (target.isNative && target.isFunction
1494 && !node.isInterceptedCall) { 1494 && !node.isInterceptedCall) {
1495 // A direct (i.e. non-interceptor) native call is the result of 1495 // A direct (i.e. non-interceptor) native call is the result of
1496 // optimization. The optimization ensures any type checks or 1496 // optimization. The optimization ensures any type checks or
1497 // conversions have been satisified. 1497 // conversions have been satisified.
1498 methodName = target.fixedBackendName(); 1498 methodName = target.fixedBackendName;
1499 } 1499 }
1500 } 1500 }
1501 1501
1502 if (methodName == null) { 1502 if (methodName == null) {
1503 methodName = backend.namer.invocationName(node.selector); 1503 methodName = backend.namer.invocationName(node.selector);
1504 registerMethodInvoke(node); 1504 registerMethodInvoke(node);
1505 } 1505 }
1506 push(jsPropertyCall(object, methodName, arguments), node); 1506 push(jsPropertyCall(object, methodName, arguments), node);
1507 } 1507 }
1508 1508
1509 void visitInvokeConstructorBody(HInvokeConstructorBody node) { 1509 void visitInvokeConstructorBody(HInvokeConstructorBody node) {
1510 use(node.inputs[0]); 1510 use(node.inputs[0]);
1511 js.Expression object = pop(); 1511 js.Expression object = pop();
1512 String methodName = backend.namer.getNameOfInstanceMember(node.element); 1512 String methodName = backend.namer.getNameOfInstanceMember(node.element);
1513 List<js.Expression> arguments = visitArguments(node.inputs); 1513 List<js.Expression> arguments = visitArguments(node.inputs);
1514 push(jsPropertyCall(object, methodName, arguments), node); 1514 push(jsPropertyCall(object, methodName, arguments), node);
1515 world.registerStaticUse(node.element); 1515 world.registerStaticUse(node.element);
1516 } 1516 }
1517 1517
1518 void visitOneShotInterceptor(HOneShotInterceptor node) { 1518 void visitOneShotInterceptor(HOneShotInterceptor node) {
1519 List<js.Expression> arguments = visitArguments(node.inputs); 1519 List<js.Expression> arguments = visitArguments(node.inputs);
1520 var isolate = new js.VariableUse( 1520 var isolate = new js.VariableUse(
1521 backend.namer.globalObjectFor(compiler.interceptorsLibrary)); 1521 backend.namer.globalObjectFor(compiler.interceptorsLibrary));
1522 Selector selector = getOptimizedSelectorFor(node, node.selector); 1522 Selector selector = getOptimizedSelectorFor(node, node.selector);
1523 String methodName = backend.registerOneShotInterceptor(selector); 1523 String methodName = backend.registerOneShotInterceptor(selector);
1524 push(jsPropertyCall(isolate, methodName, arguments), node); 1524 push(jsPropertyCall(isolate, methodName, arguments), node);
1525 if (selector.isGetter()) { 1525 if (selector.isGetter) {
1526 registerGetter(node); 1526 registerGetter(node);
1527 } else if (selector.isSetter()) { 1527 } else if (selector.isSetter) {
1528 registerSetter(node); 1528 registerSetter(node);
1529 } else { 1529 } else {
1530 registerMethodInvoke(node); 1530 registerMethodInvoke(node);
1531 } 1531 }
1532 backend.registerUseInterceptor(world); 1532 backend.registerUseInterceptor(world);
1533 } 1533 }
1534 1534
1535 Selector getOptimizedSelectorFor(HInvokeDynamic node, Selector selector) { 1535 Selector getOptimizedSelectorFor(HInvokeDynamic node, Selector selector) {
1536 if (node.element != null) { 1536 if (node.element != null) {
1537 // Create an artificial type mask to make sure only 1537 // Create an artificial type mask to make sure only
1538 // [node.element] will be enqueued. We're not using the receiver 1538 // [node.element] will be enqueued. We're not using the receiver
1539 // type because our optimizations might end up in a state where the 1539 // type because our optimizations might end up in a state where the
1540 // invoke dynamic knows more than the receiver. 1540 // invoke dynamic knows more than the receiver.
1541 ClassElement enclosing = node.element.getEnclosingClass(); 1541 ClassElement enclosing = node.element.enclosingClass;
1542 TypeMask receiverType = new TypeMask.nonNullExact(enclosing.declaration); 1542 TypeMask receiverType = new TypeMask.nonNullExact(enclosing.declaration);
1543 return new TypedSelector(receiverType, selector); 1543 return new TypedSelector(receiverType, selector);
1544 } 1544 }
1545 // If [JSInvocationMirror._invokeOn] is enabled, and this call 1545 // If [JSInvocationMirror._invokeOn] is enabled, and this call
1546 // might hit a `noSuchMethod`, we register an untyped selector. 1546 // might hit a `noSuchMethod`, we register an untyped selector.
1547 return selector.extendIfReachesAll(compiler); 1547 return selector.extendIfReachesAll(compiler);
1548 } 1548 }
1549 1549
1550 void registerMethodInvoke(HInvokeDynamic node) { 1550 void registerMethodInvoke(HInvokeDynamic node) {
1551 Selector selector = getOptimizedSelectorFor(node, node.selector); 1551 Selector selector = getOptimizedSelectorFor(node, node.selector);
1552 1552
1553 // If we don't know what we're calling or if we are calling a getter, 1553 // If we don't know what we're calling or if we are calling a getter,
1554 // we need to register that fact that we may be calling a closure 1554 // we need to register that fact that we may be calling a closure
1555 // with the same arguments. 1555 // with the same arguments.
1556 Element target = node.element; 1556 Element target = node.element;
1557 if (target == null || target.isGetter()) { 1557 if (target == null || target.isGetter) {
1558 // TODO(kasperl): If we have a typed selector for the call, we 1558 // TODO(kasperl): If we have a typed selector for the call, we
1559 // may know something about the types of closures that need 1559 // may know something about the types of closures that need
1560 // the specific closure call method. 1560 // the specific closure call method.
1561 Selector call = new Selector.callClosureFrom(selector); 1561 Selector call = new Selector.callClosureFrom(selector);
1562 world.registerDynamicInvocation(call); 1562 world.registerDynamicInvocation(call);
1563 } 1563 }
1564 world.registerDynamicInvocation(selector); 1564 world.registerDynamicInvocation(selector);
1565 } 1565 }
1566 1566
1567 void registerSetter(HInvokeDynamic node) { 1567 void registerSetter(HInvokeDynamic node) {
(...skipping 25 matching lines...) Expand all
1593 use(node.receiver); 1593 use(node.receiver);
1594 push(jsPropertyCall(pop(), 1594 push(jsPropertyCall(pop(),
1595 backend.namer.invocationName(call), 1595 backend.namer.invocationName(call),
1596 visitArguments(node.inputs)), 1596 visitArguments(node.inputs)),
1597 node); 1597 node);
1598 world.registerDynamicInvocation(call); 1598 world.registerDynamicInvocation(call);
1599 } 1599 }
1600 1600
1601 visitInvokeStatic(HInvokeStatic node) { 1601 visitInvokeStatic(HInvokeStatic node) {
1602 Element element = node.element; 1602 Element element = node.element;
1603 ClassElement cls = element.getEnclosingClass(); 1603 ClassElement cls = element.enclosingClass;
1604 List<DartType> instantiatedTypes = node.instantiatedTypes; 1604 List<DartType> instantiatedTypes = node.instantiatedTypes;
1605 1605
1606 world.registerStaticUse(element); 1606 world.registerStaticUse(element);
1607 1607
1608 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { 1608 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) {
1609 instantiatedTypes.forEach((type) { 1609 instantiatedTypes.forEach((type) {
1610 world.registerInstantiatedType(type, work.resolutionTree); 1610 world.registerInstantiatedType(type, work.resolutionTree);
1611 }); 1611 });
1612 } 1612 }
1613 1613
1614 push(backend.namer.elementAccess(node.element)); 1614 push(backend.namer.elementAccess(node.element));
1615 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); 1615 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node);
1616 } 1616 }
1617 1617
1618 visitInvokeSuper(HInvokeSuper node) { 1618 visitInvokeSuper(HInvokeSuper node) {
1619 Element superMethod = node.element; 1619 Element superMethod = node.element;
1620 world.registerStaticUse(superMethod); 1620 world.registerStaticUse(superMethod);
1621 ClassElement superClass = superMethod.getEnclosingClass(); 1621 ClassElement superClass = superMethod.enclosingClass;
1622 if (superMethod.kind == ElementKind.FIELD) { 1622 if (superMethod.kind == ElementKind.FIELD) {
1623 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); 1623 String fieldName = backend.namer.instanceFieldPropertyName(superMethod);
1624 use(node.inputs[0]); 1624 use(node.inputs[0]);
1625 js.PropertyAccess access = 1625 js.PropertyAccess access =
1626 new js.PropertyAccess.field(pop(), fieldName); 1626 new js.PropertyAccess.field(pop(), fieldName);
1627 if (node.isSetter) { 1627 if (node.isSetter) {
1628 use(node.value); 1628 use(node.value);
1629 push(new js.Assignment(access, pop()), node); 1629 push(new js.Assignment(access, pop()), node);
1630 } else { 1630 } else {
1631 push(access, node); 1631 push(access, node);
1632 } 1632 }
1633 } else { 1633 } else {
1634 Selector selector = node.selector; 1634 Selector selector = node.selector;
1635 String methodName; 1635 String methodName;
1636 if (selector.isGetter()) { 1636 if (selector.isGetter) {
1637 // If the selector we need to register a typed getter to the 1637 // If the selector we need to register a typed getter to the
1638 // [world]. The emitter needs to know if it needs to emit a 1638 // [world]. The emitter needs to know if it needs to emit a
1639 // bound closure for a method. 1639 // bound closure for a method.
1640 TypeMask receiverType = new TypeMask.nonNullExact(superClass); 1640 TypeMask receiverType = new TypeMask.nonNullExact(superClass);
1641 selector = new TypedSelector(receiverType, selector); 1641 selector = new TypedSelector(receiverType, selector);
1642 // TODO(floitsch): we know the target. We shouldn't register a 1642 // TODO(floitsch): we know the target. We shouldn't register a
1643 // dynamic getter. 1643 // dynamic getter.
1644 world.registerDynamicGetter(selector); 1644 world.registerDynamicGetter(selector);
1645 world.registerGetterForSuperMethod(node.element); 1645 world.registerGetterForSuperMethod(node.element);
1646 methodName = backend.namer.invocationName(selector); 1646 methodName = backend.namer.invocationName(selector);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1767 void generateConstant(Constant constant) { 1767 void generateConstant(Constant constant) {
1768 if (constant.isFunction) { 1768 if (constant.isFunction) {
1769 FunctionConstant function = constant; 1769 FunctionConstant function = constant;
1770 world.registerStaticUse(function.element); 1770 world.registerStaticUse(function.element);
1771 } 1771 }
1772 if (constant.isType) { 1772 if (constant.isType) {
1773 // If the type is a web component, we need to ensure the constructors are 1773 // If the type is a web component, we need to ensure the constructors are
1774 // available to 'upgrade' the native object. 1774 // available to 'upgrade' the native object.
1775 TypeConstant type = constant; 1775 TypeConstant type = constant;
1776 Element element = type.representedType.element; 1776 Element element = type.representedType.element;
1777 if (element != null && element.isClass()) { 1777 if (element != null && element.isClass) {
1778 backend.customElementsAnalysis.registerTypeConstant(element, world); 1778 backend.customElementsAnalysis.registerTypeConstant(element, world);
1779 } 1779 }
1780 } 1780 }
1781 push(backend.emitter.constantReference(constant)); 1781 push(backend.emitter.constantReference(constant));
1782 } 1782 }
1783 1783
1784 visitConstant(HConstant node) { 1784 visitConstant(HConstant node) {
1785 assert(isGenerateAtUseSite(node)); 1785 assert(isGenerateAtUseSite(node));
1786 generateConstant(node.constant); 1786 generateConstant(node.constant);
1787 1787
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
2019 value = attachLocation(value, argument); 2019 value = attachLocation(value, argument);
2020 push(value, node); 2020 push(value, node);
2021 } 2021 }
2022 2022
2023 void visitSwitch(HSwitch node) { 2023 void visitSwitch(HSwitch node) {
2024 // Switches are handled using [visitSwitchInfo]. 2024 // Switches are handled using [visitSwitchInfo].
2025 } 2025 }
2026 2026
2027 void visitStatic(HStatic node) { 2027 void visitStatic(HStatic node) {
2028 Element element = node.element; 2028 Element element = node.element;
2029 if (element.isFunction()) { 2029 if (element.isFunction) {
2030 push(backend.namer.isolateStaticClosureAccess(node.element)); 2030 push(backend.namer.isolateStaticClosureAccess(node.element));
2031 } else { 2031 } else {
2032 push(backend.namer.elementAccess(node.element)); 2032 push(backend.namer.elementAccess(node.element));
2033 } 2033 }
2034 world.registerStaticUse(element); 2034 world.registerStaticUse(element);
2035 } 2035 }
2036 2036
2037 void visitLazyStatic(HLazyStatic node) { 2037 void visitLazyStatic(HLazyStatic node) {
2038 Element element = node.element; 2038 Element element = node.element;
2039 world.registerStaticUse(element); 2039 world.registerStaticUse(element);
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after
2622 } 2622 }
2623 } 2623 }
2624 2624
2625 void visitReadTypeVariable(HReadTypeVariable node) { 2625 void visitReadTypeVariable(HReadTypeVariable node) {
2626 TypeVariableElement element = node.dartType.element; 2626 TypeVariableElement element = node.dartType.element;
2627 Element helperElement = compiler.findHelper('convertRtiToRuntimeType'); 2627 Element helperElement = compiler.findHelper('convertRtiToRuntimeType');
2628 world.registerStaticUse(helperElement); 2628 world.registerStaticUse(helperElement);
2629 2629
2630 use(node.inputs[0]); 2630 use(node.inputs[0]);
2631 if (node.hasReceiver) { 2631 if (node.hasReceiver) {
2632 if (backend.isInterceptorClass(element.getEnclosingClass())) { 2632 if (backend.isInterceptorClass(element.enclosingClass)) {
2633 int index = RuntimeTypes.getTypeVariableIndex(element); 2633 int index = RuntimeTypes.getTypeVariableIndex(element);
2634 js.Expression receiver = pop(); 2634 js.Expression receiver = pop();
2635 js.Expression helper = backend.namer.elementAccess(helperElement); 2635 js.Expression helper = backend.namer.elementAccess(helperElement);
2636 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', 2636 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])',
2637 [helper, receiver, receiver, js.js.number(index)])); 2637 [helper, receiver, receiver, js.js.number(index)]));
2638 } else { 2638 } else {
2639 backend.emitter.registerReadTypeVariable(element); 2639 backend.emitter.registerReadTypeVariable(element);
2640 push(js.js('#.#()', 2640 push(js.js('#.#()',
2641 [pop(), backend.namer.readTypeVariableName(element)])); 2641 [pop(), backend.namer.readTypeVariableName(element)]));
2642 } 2642 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2674 js.PropertyAccess accessHelper(String name) { 2674 js.PropertyAccess accessHelper(String name) {
2675 Element helper = compiler.findHelper(name); 2675 Element helper = compiler.findHelper(name);
2676 if (helper == null) { 2676 if (helper == null) {
2677 // For mocked-up tests. 2677 // For mocked-up tests.
2678 return js.js('(void 0).$name'); 2678 return js.js('(void 0).$name');
2679 } 2679 }
2680 world.registerStaticUse(helper); 2680 world.registerStaticUse(helper);
2681 return backend.namer.elementAccess(helper); 2681 return backend.namer.elementAccess(helper);
2682 } 2682 }
2683 } 2683 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698