OLD | NEW |
---|---|
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 |
(...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1522 } | 1522 } |
1523 } | 1523 } |
1524 | 1524 |
1525 js.Call jsPropertyCall(js.Expression receiver, | 1525 js.Call jsPropertyCall(js.Expression receiver, |
1526 String fieldName, | 1526 String fieldName, |
1527 List<js.Expression> arguments) { | 1527 List<js.Expression> arguments) { |
1528 return new js.Call(new js.PropertyAccess.field(receiver, fieldName), | 1528 return new js.Call(new js.PropertyAccess.field(receiver, fieldName), |
1529 arguments); | 1529 arguments); |
1530 } | 1530 } |
1531 | 1531 |
1532 // TODO(ngeoffray): Once we remove the old interceptors, we can | |
1533 // start using HInvokeInterceptor to represent interceptor calls on | |
1534 // an Interceptor class. Currently we recognize if a call is a call | |
1535 // on an interceptor by checking if the arguments in the inputs list | |
1536 // is one more than the arguments in the selector. The extra | |
1537 // argument in an interceptor call is the actual receiver. | |
1538 bool isInterceptorCall(HInvokeDynamic node) { | |
1539 return node.inputs.length - 1 != node.selector.argumentCount; | |
1540 } | |
1541 | |
1542 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1532 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
1543 use(node.receiver); | 1533 use(node.receiver); |
1544 js.Expression object = pop(); | 1534 js.Expression object = pop(); |
1545 SourceString name = node.selector.name; | 1535 SourceString name = node.selector.name; |
1546 String methodName; | 1536 String methodName; |
1547 List<js.Expression> arguments; | 1537 List<js.Expression> arguments; |
1548 Element target = node.element; | 1538 Element target = node.element; |
1549 | 1539 |
1550 // Avoid adding the generative constructor name to the list of | 1540 // Avoid adding the generative constructor name to the list of |
1551 // seen selectors. | 1541 // seen selectors. |
1552 if (target != null && target.isGenerativeConstructorBody()) { | 1542 if (target != null && target.isGenerativeConstructorBody()) { |
1553 methodName = name.slowToString(); | 1543 methodName = name.slowToString(); |
1554 arguments = visitArguments(node.inputs); | 1544 arguments = visitArguments(node.inputs); |
1555 } else { | 1545 } else { |
1556 methodName = backend.namer.instanceMethodInvocationName( | 1546 methodName = backend.namer.instanceMethodInvocationName( |
1557 node.selector.library, name, node.selector); | 1547 node.selector.library, name, node.selector); |
1558 arguments = visitArguments(node.inputs); | 1548 arguments = visitArguments(node.inputs); |
1559 bool inLoop = node.block.enclosingLoopHeader != null; | 1549 bool inLoop = node.block.enclosingLoopHeader != null; |
1560 | 1550 |
1561 // Register this invocation to collect the types used at all call sites. | 1551 // Register this invocation to collect the types used at all call sites. |
1562 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1552 Selector selector = getOptimizedSelectorFor(node, node.selector); |
1563 // TODO(ngeoffray): Remove the following restriction. Because | 1553 // TODO(ngeoffray): Remove the following restriction. Because |
1564 // the second input of this interceptor call is the actual | 1554 // the second input of this interceptor call is the actual |
1565 // receiver (the first is the interceptor), the backend gets | 1555 // receiver (the first is the interceptor), the backend gets |
1566 // confused. We should pass a list of types instead of a node to | 1556 // confused. We should pass a list of types instead of a node to |
1567 // [registerDynamicInvocation]. | 1557 // [registerDynamicInvocation]. |
1568 if (!isInterceptorCall(node)) { | 1558 if (!node.isInterceptorCall) { |
1569 backend.registerDynamicInvocation(node, selector, types); | 1559 backend.registerDynamicInvocation(node, selector, types); |
1570 } else { | 1560 } else { |
1571 backend.addInterceptedSelector(selector); | 1561 backend.addInterceptedSelector(selector); |
1572 } | 1562 } |
1573 | 1563 |
1574 // If we don't know what we're calling or if we are calling a getter, | 1564 // If we don't know what we're calling or if we are calling a getter, |
1575 // we need to register that fact that we may be calling a closure | 1565 // we need to register that fact that we may be calling a closure |
1576 // with the same arguments. | 1566 // with the same arguments. |
1577 if (target == null || target.isGetter()) { | 1567 if (target == null || target.isGetter()) { |
1578 // TODO(kasperl): If we have a typed selector for the call, we | 1568 // TODO(kasperl): If we have a typed selector for the call, we |
(...skipping 14 matching lines...) Expand all Loading... | |
1593 } | 1583 } |
1594 } | 1584 } |
1595 push(jsPropertyCall(object, methodName, arguments), node); | 1585 push(jsPropertyCall(object, methodName, arguments), node); |
1596 } | 1586 } |
1597 | 1587 |
1598 Selector getOptimizedSelectorFor(HInvokeDynamic node, | 1588 Selector getOptimizedSelectorFor(HInvokeDynamic node, |
1599 Selector defaultSelector) { | 1589 Selector defaultSelector) { |
1600 // TODO(4434): For private members we need to use the untyped selector. | 1590 // TODO(4434): For private members we need to use the untyped selector. |
1601 if (defaultSelector.name.isPrivate()) return defaultSelector; | 1591 if (defaultSelector.name.isPrivate()) return defaultSelector; |
1602 // TODO(ngeoffray): Type intercepted calls. | 1592 // TODO(ngeoffray): Type intercepted calls. |
1603 if (isInterceptorCall(node)) return defaultSelector; | 1593 if (node.isInterceptorCall) return defaultSelector; |
1604 // If [JSInvocationMirror.invokeOn] has been called, we must not create a | 1594 // If [JSInvocationMirror.invokeOn] has been called, we must not create a |
1605 // typed selector based on the receiver type. | 1595 // typed selector based on the receiver type. |
1606 if (node.element == null && // Invocation is not exact. | 1596 if (node.element == null && // Invocation is not exact. |
1607 backend.compiler.enabledInvokeOn) { | 1597 backend.compiler.enabledInvokeOn) { |
1608 return defaultSelector; | 1598 return defaultSelector; |
1609 } | 1599 } |
1610 HType receiverHType = types[node.inputs[0]]; | 1600 HType receiverHType = types[node.inputs[0]]; |
1611 DartType receiverType = receiverHType.computeType(compiler); | 1601 DartType receiverType = receiverHType.computeType(compiler); |
1612 if (receiverType != null) { | 1602 if (receiverType != null) { |
1613 return new TypedSelector(receiverType, defaultSelector); | 1603 return new TypedSelector(receiverType, defaultSelector); |
1614 } else { | 1604 } else { |
1615 return defaultSelector; | 1605 return defaultSelector; |
1616 } | 1606 } |
1617 } | 1607 } |
1618 | 1608 |
1619 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1609 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
1620 use(node.receiver); | 1610 use(node.receiver); |
1621 Selector setter = node.selector; | 1611 Selector setter = node.selector; |
1622 String name = backend.namer.setterName(setter.library, setter.name); | 1612 String name = backend.namer.setterName(setter.library, setter.name); |
1623 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); | 1613 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); |
1624 Selector selector = getOptimizedSelectorFor(node, setter); | 1614 Selector selector = getOptimizedSelectorFor(node, setter); |
1625 world.registerDynamicSetter(setter.name, selector); | 1615 world.registerDynamicSetter(setter.name, selector); |
1626 backend.addedDynamicSetter(selector, types[node.inputs[1]]); | 1616 HType valueType; |
1617 if (node.isInterceptorCall) { | |
1618 valueType = types[node.inputs[2]]; | |
1619 backend.addInterceptedSelector(setter); | |
1620 } else { | |
1621 valueType = types[node.inputs[1]]; | |
1622 } | |
1623 backend.addedDynamicSetter(selector, valueType); | |
1627 } | 1624 } |
1628 | 1625 |
1629 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1626 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
1630 use(node.receiver); | 1627 use(node.receiver); |
1631 Selector getter = node.selector; | 1628 Selector getter = node.selector; |
1632 String name = backend.namer.getterName(getter.library, getter.name); | 1629 String name = backend.namer.getterName(getter.library, getter.name); |
1633 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); | 1630 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); |
1634 world.registerDynamicGetter( | 1631 world.registerDynamicGetter( |
1635 getter.name, getOptimizedSelectorFor(node, getter)); | 1632 getter.name, getOptimizedSelectorFor(node, getter)); |
1636 if (isInterceptorCall(node)) { | 1633 if (node.isInterceptorCall) { |
1637 backend.addInterceptedSelector(getter); | 1634 backend.addInterceptedSelector(getter); |
1638 } | 1635 } |
1639 } | 1636 } |
1640 | 1637 |
1641 visitInvokeClosure(HInvokeClosure node) { | 1638 visitInvokeClosure(HInvokeClosure node) { |
1642 use(node.receiver); | 1639 use(node.receiver); |
1643 push(jsPropertyCall(pop(), | 1640 push(jsPropertyCall(pop(), |
1644 backend.namer.closureInvocationName(node.selector), | 1641 backend.namer.closureInvocationName(node.selector), |
1645 visitArguments(node.inputs)), | 1642 visitArguments(node.inputs)), |
1646 node); | 1643 node); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1707 js.VariableUse classReference = new js.VariableUse(className); | 1704 js.VariableUse classReference = new js.VariableUse(className); |
1708 js.PropertyAccess prototype = | 1705 js.PropertyAccess prototype = |
1709 new js.PropertyAccess.field(classReference, "prototype"); | 1706 new js.PropertyAccess.field(classReference, "prototype"); |
1710 js.PropertyAccess method = | 1707 js.PropertyAccess method = |
1711 new js.PropertyAccess.field(prototype, methodName); | 1708 new js.PropertyAccess.field(prototype, methodName); |
1712 push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); | 1709 push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); |
1713 } | 1710 } |
1714 world.registerStaticUse(superMethod); | 1711 world.registerStaticUse(superMethod); |
1715 } | 1712 } |
1716 | 1713 |
1717 visitFieldGet(HFieldGet node) { | 1714 visitFieldGet(HFieldGet node) { |
ahe
2012/11/23 06:51:23
What is a HFieldGet? Is that when we know that we
ngeoffray
2012/11/23 12:01:17
Yes.
| |
1718 String name = backend.namer.getName(node.element); | |
1719 use(node.receiver); | 1715 use(node.receiver); |
1720 push(new js.PropertyAccess.field(pop(), name), node); | 1716 if (node.element == backend.jsArrayLength |
1721 HType receiverHType = types[node.receiver]; | 1717 || node.element == backend.jsStringLength) { |
1722 DartType type = receiverHType.computeType(compiler); | 1718 push(new js.PropertyAccess.field(pop(), 'length'), node); |
ahe
2012/11/23 06:51:23
Please add a comment explaining why this name shou
ngeoffray
2012/11/23 12:01:17
Done.
| |
1723 if (type != null) { | 1719 } else { |
1724 world.registerFieldGetter( | 1720 String name = backend.namer.getName(node.element); |
1725 node.element.name, node.element.getLibrary(), type); | 1721 push(new js.PropertyAccess.field(pop(), name), node); |
1722 HType receiverHType = types[node.receiver]; | |
1723 DartType type = receiverHType.computeType(compiler); | |
1724 if (type != null) { | |
1725 world.registerFieldGetter( | |
1726 node.element.name, node.element.getLibrary(), type); | |
1727 } | |
1726 } | 1728 } |
1727 } | 1729 } |
1728 | 1730 |
1729 // Determine if an instruction is a simple number computation | 1731 // Determine if an instruction is a simple number computation |
1730 // involving only things with guaranteed number types and a given | 1732 // involving only things with guaranteed number types and a given |
1731 // field. | 1733 // field. |
1732 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { | 1734 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { |
1733 if (value.guaranteedType.union(HType.NUMBER, compiler) == HType.NUMBER) { | 1735 if (value.guaranteedType.union(HType.NUMBER, compiler) == HType.NUMBER) { |
1734 return true; | 1736 return true; |
1735 } | 1737 } |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2191 use(node.inputs[2]); | 2193 use(node.inputs[2]); |
2192 js.Expression index = pop(); | 2194 js.Expression index = pop(); |
2193 use(node.inputs[3]); | 2195 use(node.inputs[3]); |
2194 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), | 2196 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), |
2195 node); | 2197 node); |
2196 } else { | 2198 } else { |
2197 visitInvokeStatic(node); | 2199 visitInvokeStatic(node); |
2198 } | 2200 } |
2199 } | 2201 } |
2200 | 2202 |
2201 String builtinJsName(HInvokeInterceptor interceptor) { | |
2202 // Don't count the target method or the receiver in the arity. | |
2203 int arity = interceptor.inputs.length - 2; | |
2204 HInstruction receiver = interceptor.inputs[1]; | |
2205 bool isCall = interceptor.selector.isCall(); | |
2206 SourceString name = interceptor.selector.name; | |
2207 | |
2208 if (interceptor.isLengthGetterOnStringOrArray(types)) { | |
2209 return 'length'; | |
2210 } else if (interceptor.isPopCall(types)) { | |
2211 return 'pop'; | |
2212 } else if (receiver.isExtendableArray(types) && isCall) { | |
2213 if (name == const SourceString('add') && arity == 1) { | |
2214 return 'push'; | |
2215 } | |
2216 } else if (receiver.isString(types) && isCall) { | |
2217 if (name == const SourceString('concat') && | |
2218 arity == 1 && | |
2219 interceptor.inputs[2].isString(types)) { | |
2220 return '+'; | |
2221 } | |
2222 if (name == const SourceString('split') && | |
2223 arity == 1 && | |
2224 interceptor.inputs[2].isString(types)) { | |
2225 return 'split'; | |
2226 } | |
2227 } | |
2228 | |
2229 return null; | |
2230 } | |
2231 | |
2232 void visitInvokeInterceptor(HInvokeInterceptor node) { | |
2233 String builtin = builtinJsName(node); | |
2234 if (builtin != null) { | |
2235 if (builtin == '+') { | |
2236 use(node.inputs[1]); | |
2237 js.Expression left = pop(); | |
2238 use(node.inputs[2]); | |
2239 push(new js.Binary("+", left, pop()), node); | |
2240 } else { | |
2241 use(node.inputs[1]); | |
2242 js.PropertyAccess access = new js.PropertyAccess.field(pop(), builtin); | |
2243 if (node.selector.isGetter()) { | |
2244 push(access, node); | |
2245 return; | |
2246 } | |
2247 List<js.Expression> arguments = <js.Expression>[]; | |
2248 for (int i = 2; i < node.inputs.length; i++) { | |
2249 use(node.inputs[i]); | |
2250 arguments.add(pop()); | |
2251 } | |
2252 push(new js.Call(access, arguments), node); | |
2253 } | |
2254 } else { | |
2255 return visitInvokeStatic(node); | |
2256 } | |
2257 } | |
2258 | |
2259 void checkInt(HInstruction input, String cmp) { | 2203 void checkInt(HInstruction input, String cmp) { |
2260 use(input); | 2204 use(input); |
2261 js.Expression left = pop(); | 2205 js.Expression left = pop(); |
2262 use(input); | 2206 use(input); |
2263 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); | 2207 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); |
2264 push(new js.Binary(cmp, left, or0)); | 2208 push(new js.Binary(cmp, left, or0)); |
2265 } | 2209 } |
2266 | 2210 |
2267 void checkBigInt(HInstruction input, String cmp) { | 2211 void checkBigInt(HInstruction input, String cmp) { |
2268 use(input); | 2212 use(input); |
(...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3110 if (leftType.canBeNull() && rightType.canBeNull()) { | 3054 if (leftType.canBeNull() && rightType.canBeNull()) { |
3111 if (left.isConstantNull() || right.isConstantNull() || | 3055 if (left.isConstantNull() || right.isConstantNull() || |
3112 (leftType.isPrimitive() && leftType == rightType)) { | 3056 (leftType.isPrimitive() && leftType == rightType)) { |
3113 return '=='; | 3057 return '=='; |
3114 } | 3058 } |
3115 return null; | 3059 return null; |
3116 } else { | 3060 } else { |
3117 return '==='; | 3061 return '==='; |
3118 } | 3062 } |
3119 } | 3063 } |
OLD | NEW |