OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/compiler/access-builder.h" | 6 #include "src/compiler/access-builder.h" |
7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
9 #include "src/compiler/linkage.h" | 9 #include "src/compiler/linkage.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
837 Node* const input = node->InputAt(0); | 837 Node* const input = node->InputAt(0); |
838 Reduction reduction = ReduceJSToStringInput(input); | 838 Reduction reduction = ReduceJSToStringInput(input); |
839 if (reduction.Changed()) { | 839 if (reduction.Changed()) { |
840 ReplaceWithValue(node, reduction.replacement()); | 840 ReplaceWithValue(node, reduction.replacement()); |
841 return reduction; | 841 return reduction; |
842 } | 842 } |
843 return NoChange(); | 843 return NoChange(); |
844 } | 844 } |
845 | 845 |
846 | 846 |
| 847 Reduction JSTypedLowering::ReduceJSToObject(Node* node) { |
| 848 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); |
| 849 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 850 Type* receiver_type = NodeProperties::GetType(receiver); |
| 851 Node* context = NodeProperties::GetContextInput(node); |
| 852 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 853 Node* effect = NodeProperties::GetEffectInput(node); |
| 854 Node* control = NodeProperties::GetControlInput(node); |
| 855 if (!receiver_type->Is(Type::Receiver())) { |
| 856 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks. |
| 857 if (receiver_type->Maybe(Type::NullOrUndefined()) && |
| 858 NodeProperties::IsExceptionalCall(node)) { |
| 859 // ToObject throws for null or undefined inputs. |
| 860 return NoChange(); |
| 861 } |
| 862 |
| 863 // Check whether {receiver} is a Smi. |
| 864 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
| 865 Node* branch0 = |
| 866 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); |
| 867 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 868 Node* etrue0 = effect; |
| 869 |
| 870 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 871 Node* efalse0 = effect; |
| 872 |
| 873 // Determine the instance type of {receiver}. |
| 874 Node* receiver_map = efalse0 = |
| 875 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 876 receiver, efalse0, if_false0); |
| 877 Node* receiver_instance_type = efalse0 = graph()->NewNode( |
| 878 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |
| 879 receiver_map, efalse0, if_false0); |
| 880 |
| 881 // Check whether {receiver} is a spec object. |
| 882 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 883 Node* check1 = |
| 884 graph()->NewNode(machine()->Uint32LessThanOrEqual(), |
| 885 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE), |
| 886 receiver_instance_type); |
| 887 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 888 check1, if_false0); |
| 889 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 890 Node* etrue1 = efalse0; |
| 891 |
| 892 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 893 Node* efalse1 = efalse0; |
| 894 |
| 895 // Convert {receiver} using the ToObjectStub. |
| 896 Node* if_convert = |
| 897 graph()->NewNode(common()->Merge(2), if_true0, if_false1); |
| 898 Node* econvert = |
| 899 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert); |
| 900 Node* rconvert; |
| 901 { |
| 902 Callable callable = CodeFactory::ToObject(isolate()); |
| 903 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
| 904 isolate(), graph()->zone(), callable.descriptor(), 0, |
| 905 CallDescriptor::kNeedsFrameState, node->op()->properties()); |
| 906 rconvert = econvert = graph()->NewNode( |
| 907 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), |
| 908 receiver, context, frame_state, econvert, if_convert); |
| 909 } |
| 910 |
| 911 // The {receiver} is already a spec object. |
| 912 Node* if_done = if_true1; |
| 913 Node* edone = etrue1; |
| 914 Node* rdone = receiver; |
| 915 |
| 916 control = graph()->NewNode(common()->Merge(2), if_convert, if_done); |
| 917 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control); |
| 918 receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert, |
| 919 rdone, control); |
| 920 } |
| 921 ReplaceWithValue(node, receiver, effect, control); |
| 922 return Changed(receiver); |
| 923 } |
| 924 |
| 925 |
847 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { | 926 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { |
848 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); | 927 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); |
849 Node* receiver = NodeProperties::GetValueInput(node, 0); | 928 Node* receiver = NodeProperties::GetValueInput(node, 0); |
850 Type* receiver_type = NodeProperties::GetType(receiver); | 929 Type* receiver_type = NodeProperties::GetType(receiver); |
851 Node* effect = NodeProperties::GetEffectInput(node); | 930 Node* effect = NodeProperties::GetEffectInput(node); |
852 Node* control = NodeProperties::GetControlInput(node); | 931 Node* control = NodeProperties::GetControlInput(node); |
853 Handle<Name> name = NamedAccessOf(node->op()).name(); | 932 Handle<Name> name = NamedAccessOf(node->op()).name(); |
854 // Optimize "length" property of strings. | 933 // Optimize "length" property of strings. |
855 if (name.is_identical_to(factory()->length_string()) && | 934 if (name.is_identical_to(factory()->length_string()) && |
856 receiver_type->Is(Type::String())) { | 935 receiver_type->Is(Type::String())) { |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 graph()->NewNode(simplified()->LoadField( | 1253 graph()->NewNode(simplified()->LoadField( |
1175 AccessBuilder::ForGlobalObjectGlobalProxy()), | 1254 AccessBuilder::ForGlobalObjectGlobalProxy()), |
1176 global_object, effect, control); | 1255 global_object, effect, control); |
1177 } | 1256 } |
1178 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) || | 1257 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) || |
1179 mode == ConvertReceiverMode::kNotNullOrUndefined) { | 1258 mode == ConvertReceiverMode::kNotNullOrUndefined) { |
1180 receiver = effect = | 1259 receiver = effect = |
1181 graph()->NewNode(javascript()->ToObject(), receiver, context, | 1260 graph()->NewNode(javascript()->ToObject(), receiver, context, |
1182 frame_state, effect, control); | 1261 frame_state, effect, control); |
1183 } else { | 1262 } else { |
1184 return NoChange(); | 1263 // Check {receiver} for undefined. |
| 1264 Node* check0 = |
| 1265 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), |
| 1266 receiver, jsgraph()->UndefinedConstant()); |
| 1267 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1268 check0, control); |
| 1269 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1270 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1271 |
| 1272 // Check {receiver} for null. |
| 1273 Node* check1 = |
| 1274 graph()->NewNode(simplified()->ReferenceEqual(receiver_type), |
| 1275 receiver, jsgraph()->NullConstant()); |
| 1276 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1277 check1, if_false0); |
| 1278 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1279 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1280 |
| 1281 // Convert {receiver} using ToObject. |
| 1282 Node* if_convert = if_false1; |
| 1283 Node* econvert = effect; |
| 1284 Node* rconvert; |
| 1285 { |
| 1286 rconvert = econvert = |
| 1287 graph()->NewNode(javascript()->ToObject(), receiver, context, |
| 1288 frame_state, econvert, if_convert); |
| 1289 } |
| 1290 |
| 1291 // Replace {receiver} with global proxy of {context}. |
| 1292 Node* if_global = |
| 1293 graph()->NewNode(common()->Merge(2), if_true0, if_true1); |
| 1294 Node* eglobal = effect; |
| 1295 Node* rglobal; |
| 1296 { |
| 1297 if (context_type->IsConstant()) { |
| 1298 Handle<JSObject> global_proxy( |
| 1299 Handle<Context>::cast(context_type->AsConstant()->Value()) |
| 1300 ->global_proxy(), |
| 1301 isolate()); |
| 1302 rglobal = jsgraph()->Constant(global_proxy); |
| 1303 } else { |
| 1304 Node* global_object = eglobal = graph()->NewNode( |
| 1305 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true), |
| 1306 context, context, eglobal); |
| 1307 rglobal = eglobal = |
| 1308 graph()->NewNode(simplified()->LoadField( |
| 1309 AccessBuilder::ForGlobalObjectGlobalProxy()), |
| 1310 global_object, eglobal, if_global); |
| 1311 } |
| 1312 } |
| 1313 |
| 1314 control = graph()->NewNode(common()->Merge(2), if_convert, if_global); |
| 1315 effect = |
| 1316 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control); |
| 1317 receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert, |
| 1318 rglobal, control); |
1185 } | 1319 } |
1186 } | 1320 } |
1187 ReplaceWithValue(node, receiver, effect, control); | 1321 ReplaceWithValue(node, receiver, effect, control); |
1188 return Changed(receiver); | 1322 return Changed(receiver); |
1189 } | 1323 } |
1190 | 1324 |
1191 | 1325 |
1192 namespace { | 1326 namespace { |
1193 | 1327 |
1194 // Retrieves the frame state holding actual argument values. | 1328 // Retrieves the frame state holding actual argument values. |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1547 } | 1681 } |
1548 | 1682 |
1549 return NoChange(); | 1683 return NoChange(); |
1550 } | 1684 } |
1551 | 1685 |
1552 | 1686 |
1553 Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { | 1687 Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { |
1554 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); | 1688 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
1555 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); | 1689 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); |
1556 int const arity = static_cast<int>(p.arity() - 2); | 1690 int const arity = static_cast<int>(p.arity() - 2); |
| 1691 ConvertReceiverMode const convert_mode = p.convert_mode(); |
1557 Node* target = NodeProperties::GetValueInput(node, 0); | 1692 Node* target = NodeProperties::GetValueInput(node, 0); |
1558 Type* target_type = NodeProperties::GetType(target); | 1693 Type* target_type = NodeProperties::GetType(target); |
1559 Node* receiver = NodeProperties::GetValueInput(node, 1); | 1694 Node* receiver = NodeProperties::GetValueInput(node, 1); |
1560 Type* receiver_type = NodeProperties::GetType(receiver); | 1695 Type* receiver_type = NodeProperties::GetType(receiver); |
| 1696 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 1697 Node* effect = NodeProperties::GetEffectInput(node); |
| 1698 Node* control = NodeProperties::GetControlInput(node); |
1561 | 1699 |
1562 // Check if {target} is a known JSFunction. | 1700 // Check if {target} is a known JSFunction. |
1563 if (target_type->IsConstant() && | 1701 if (target_type->IsConstant() && |
1564 target_type->AsConstant()->Value()->IsJSFunction()) { | 1702 target_type->AsConstant()->Value()->IsJSFunction()) { |
1565 Handle<JSFunction> function = | 1703 Handle<JSFunction> function = |
1566 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); | 1704 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); |
1567 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); | 1705 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); |
1568 if (shared->internal_formal_parameter_count() == arity) { | 1706 if (shared->internal_formal_parameter_count() == arity) { |
1569 // Check if we need to wrap the {receiver}. | |
1570 if (is_sloppy(shared->language_mode()) && !shared->native()) { | |
1571 if (receiver_type->Is(Type::NullOrUndefined())) { | |
1572 // Change {receiver} to global proxy of {function}. | |
1573 receiver = | |
1574 jsgraph()->Constant(handle(function->global_proxy(), isolate())); | |
1575 } else if (!receiver_type->Is(Type::Receiver())) { | |
1576 // TODO(bmeurer): Add support for wrapping abitrary receivers. | |
1577 return NoChange(); | |
1578 } | |
1579 NodeProperties::ReplaceValueInput(node, receiver, 1); | |
1580 } | |
1581 | |
1582 // Grab the context from the {function}. | 1707 // Grab the context from the {function}. |
1583 Node* context = | 1708 Node* context = |
1584 jsgraph()->Constant(handle(function->context(), isolate())); | 1709 jsgraph()->Constant(handle(function->context(), isolate())); |
1585 NodeProperties::ReplaceContextInput(node, context); | 1710 NodeProperties::ReplaceContextInput(node, context); |
| 1711 |
| 1712 // Check if we need to convert the {receiver}. |
| 1713 if (is_sloppy(shared->language_mode()) && !shared->native() && |
| 1714 !receiver_type->Is(Type::Receiver())) { |
| 1715 receiver = effect = |
| 1716 graph()->NewNode(javascript()->ConvertReceiver(convert_mode), |
| 1717 receiver, context, frame_state, effect, control); |
| 1718 NodeProperties::ReplaceEffectInput(node, effect); |
| 1719 NodeProperties::ReplaceValueInput(node, receiver, 1); |
| 1720 } |
| 1721 |
| 1722 // Remove the eager bailout frame state. |
| 1723 NodeProperties::RemoveFrameStateInput(node, 1); |
| 1724 |
| 1725 // Patch {node} to a direct call. |
1586 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; | 1726 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; |
1587 if (p.AllowTailCalls()) { | 1727 if (p.AllowTailCalls()) flags |= CallDescriptor::kSupportsTailCalls; |
1588 flags |= CallDescriptor::kSupportsTailCalls; | |
1589 } | |
1590 NodeProperties::RemoveFrameStateInput(node, 1); | |
1591 NodeProperties::ChangeOp(node, | 1728 NodeProperties::ChangeOp(node, |
1592 common()->Call(Linkage::GetJSCallDescriptor( | 1729 common()->Call(Linkage::GetJSCallDescriptor( |
1593 graph()->zone(), false, 1 + arity, flags))); | 1730 graph()->zone(), false, 1 + arity, flags))); |
1594 return Changed(node); | 1731 return Changed(node); |
1595 } | 1732 } |
1596 } | 1733 } |
1597 | 1734 |
1598 return NoChange(); | 1735 return NoChange(); |
1599 } | 1736 } |
1600 | 1737 |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1936 case IrOpcode::kJSModulus: | 2073 case IrOpcode::kJSModulus: |
1937 return ReduceJSModulus(node); | 2074 return ReduceJSModulus(node); |
1938 case IrOpcode::kJSUnaryNot: | 2075 case IrOpcode::kJSUnaryNot: |
1939 return ReduceJSUnaryNot(node); | 2076 return ReduceJSUnaryNot(node); |
1940 case IrOpcode::kJSToBoolean: | 2077 case IrOpcode::kJSToBoolean: |
1941 return ReduceJSToBoolean(node); | 2078 return ReduceJSToBoolean(node); |
1942 case IrOpcode::kJSToNumber: | 2079 case IrOpcode::kJSToNumber: |
1943 return ReduceJSToNumber(node); | 2080 return ReduceJSToNumber(node); |
1944 case IrOpcode::kJSToString: | 2081 case IrOpcode::kJSToString: |
1945 return ReduceJSToString(node); | 2082 return ReduceJSToString(node); |
| 2083 case IrOpcode::kJSToObject: |
| 2084 return ReduceJSToObject(node); |
1946 case IrOpcode::kJSLoadNamed: | 2085 case IrOpcode::kJSLoadNamed: |
1947 return ReduceJSLoadNamed(node); | 2086 return ReduceJSLoadNamed(node); |
1948 case IrOpcode::kJSLoadProperty: | 2087 case IrOpcode::kJSLoadProperty: |
1949 return ReduceJSLoadProperty(node); | 2088 return ReduceJSLoadProperty(node); |
1950 case IrOpcode::kJSStoreProperty: | 2089 case IrOpcode::kJSStoreProperty: |
1951 return ReduceJSStoreProperty(node); | 2090 return ReduceJSStoreProperty(node); |
1952 case IrOpcode::kJSLoadContext: | 2091 case IrOpcode::kJSLoadContext: |
1953 return ReduceJSLoadContext(node); | 2092 return ReduceJSLoadContext(node); |
1954 case IrOpcode::kJSStoreContext: | 2093 case IrOpcode::kJSStoreContext: |
1955 return ReduceJSStoreContext(node); | 2094 return ReduceJSStoreContext(node); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2096 } | 2235 } |
2097 | 2236 |
2098 | 2237 |
2099 MachineOperatorBuilder* JSTypedLowering::machine() const { | 2238 MachineOperatorBuilder* JSTypedLowering::machine() const { |
2100 return jsgraph()->machine(); | 2239 return jsgraph()->machine(); |
2101 } | 2240 } |
2102 | 2241 |
2103 } // namespace compiler | 2242 } // namespace compiler |
2104 } // namespace internal | 2243 } // namespace internal |
2105 } // namespace v8 | 2244 } // namespace v8 |
OLD | NEW |