Chromium Code Reviews| 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 |