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) { | |
Michael Starzinger
2015/10/30 09:55:01
nit: Can we haz unit test for ReduceJSToObject?
Benedikt Meurer
2015/10/30 10:00:49
Of course :-)
| |
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 |