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/compiler/js-builtin-reducer.h" | 5 #include "src/compiler/js-builtin-reducer.h" |
6 | 6 |
7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/builtins/builtins-utils.h" |
8 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 10 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 11 #include "src/compiler/access-builder.h" |
11 #include "src/compiler/js-graph.h" | 12 #include "src/compiler/js-graph.h" |
12 #include "src/compiler/linkage.h" | 13 #include "src/compiler/linkage.h" |
13 #include "src/compiler/node-matchers.h" | 14 #include "src/compiler/node-matchers.h" |
14 #include "src/compiler/node-properties.h" | 15 #include "src/compiler/node-properties.h" |
15 #include "src/compiler/simplified-operator.h" | 16 #include "src/compiler/simplified-operator.h" |
16 #include "src/compiler/type-cache.h" | 17 #include "src/compiler/type-cache.h" |
17 #include "src/compiler/types.h" | 18 #include "src/compiler/types.h" |
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1014 // Return the new length of the {receiver}. | 1015 // Return the new length of the {receiver}. |
1015 value = graph()->NewNode(simplified()->NumberAdd(), length, | 1016 value = graph()->NewNode(simplified()->NumberAdd(), length, |
1016 jsgraph()->OneConstant()); | 1017 jsgraph()->OneConstant()); |
1017 | 1018 |
1018 ReplaceWithValue(node, value, effect, control); | 1019 ReplaceWithValue(node, value, effect, control); |
1019 return Replace(value); | 1020 return Replace(value); |
1020 } | 1021 } |
1021 return NoChange(); | 1022 return NoChange(); |
1022 } | 1023 } |
1023 | 1024 |
| 1025 // ES6 section 22.1.3.22 Array.prototype.shift ( ) |
| 1026 Reduction JSBuiltinReducer::ReduceArrayShift(Node* node) { |
| 1027 Node* target = NodeProperties::GetValueInput(node, 0); |
| 1028 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 1029 Node* context = NodeProperties::GetContextInput(node); |
| 1030 Node* frame_state = NodeProperties::GetFrameStateInput(node); |
| 1031 Node* effect = NodeProperties::GetEffectInput(node); |
| 1032 Node* control = NodeProperties::GetControlInput(node); |
| 1033 |
| 1034 // TODO(turbofan): Extend this to also handle fast holey double elements |
| 1035 // once we got the hole NaN mess sorted out in TurboFan/V8. |
| 1036 Handle<Map> receiver_map; |
| 1037 if (GetMapWitness(node).ToHandle(&receiver_map) && |
| 1038 CanInlineArrayResizeOperation(receiver_map) && |
| 1039 receiver_map->elements_kind() != FAST_HOLEY_DOUBLE_ELEMENTS) { |
| 1040 // Install code dependencies on the {receiver} prototype maps and the |
| 1041 // global array protector cell. |
| 1042 dependencies()->AssumePropertyCell(factory()->array_protector()); |
| 1043 dependencies()->AssumePrototypeMapsStable(receiver_map); |
| 1044 |
| 1045 // Load length of the {receiver}. |
| 1046 Node* length = effect = graph()->NewNode( |
| 1047 simplified()->LoadField( |
| 1048 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), |
| 1049 receiver, effect, control); |
| 1050 |
| 1051 // Return undefined if {receiver} has no elements. |
| 1052 Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length, |
| 1053 jsgraph()->ZeroConstant()); |
| 1054 Node* branch0 = |
| 1055 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); |
| 1056 |
| 1057 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1058 Node* etrue0 = effect; |
| 1059 Node* vtrue0 = jsgraph()->UndefinedConstant(); |
| 1060 |
| 1061 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1062 Node* efalse0 = effect; |
| 1063 Node* vfalse0; |
| 1064 { |
| 1065 // Check if we should take the fast-path. |
| 1066 Node* check1 = |
| 1067 graph()->NewNode(simplified()->NumberLessThanOrEqual(), length, |
| 1068 jsgraph()->Constant(JSArray::kMaxCopyElements)); |
| 1069 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 1070 check1, if_false0); |
| 1071 |
| 1072 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1073 Node* etrue1 = efalse0; |
| 1074 Node* vtrue1; |
| 1075 { |
| 1076 Node* elements = etrue1 = graph()->NewNode( |
| 1077 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), |
| 1078 receiver, etrue1, if_true1); |
| 1079 |
| 1080 // Load the first element here, which we return below. |
| 1081 vtrue1 = etrue1 = graph()->NewNode( |
| 1082 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( |
| 1083 receiver_map->elements_kind())), |
| 1084 elements, jsgraph()->ZeroConstant(), etrue1, if_true1); |
| 1085 |
| 1086 // Ensure that we aren't shifting a copy-on-write backing store. |
| 1087 if (IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { |
| 1088 elements = etrue1 = |
| 1089 graph()->NewNode(simplified()->EnsureWritableFastElements(), |
| 1090 receiver, elements, etrue1, if_true1); |
| 1091 } |
| 1092 |
| 1093 // Shift the remaining {elements} by one towards the start. |
| 1094 Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1); |
| 1095 Node* eloop = |
| 1096 graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop); |
| 1097 Node* index = graph()->NewNode( |
| 1098 common()->Phi(MachineRepresentation::kTagged, 2), |
| 1099 jsgraph()->OneConstant(), |
| 1100 jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop); |
| 1101 |
| 1102 { |
| 1103 Node* check2 = |
| 1104 graph()->NewNode(simplified()->NumberLessThan(), index, length); |
| 1105 Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop); |
| 1106 |
| 1107 if_true1 = graph()->NewNode(common()->IfFalse(), branch2); |
| 1108 etrue1 = eloop; |
| 1109 |
| 1110 Node* control = graph()->NewNode(common()->IfTrue(), branch2); |
| 1111 Node* effect = etrue1; |
| 1112 |
| 1113 ElementAccess const access = AccessBuilder::ForFixedArrayElement( |
| 1114 receiver_map->elements_kind()); |
| 1115 Node* value = effect = |
| 1116 graph()->NewNode(simplified()->LoadElement(access), elements, |
| 1117 index, effect, control); |
| 1118 effect = graph()->NewNode( |
| 1119 simplified()->StoreElement(access), elements, |
| 1120 graph()->NewNode(simplified()->NumberSubtract(), index, |
| 1121 jsgraph()->OneConstant()), |
| 1122 value, effect, control); |
| 1123 |
| 1124 loop->ReplaceInput(1, control); |
| 1125 eloop->ReplaceInput(1, effect); |
| 1126 index->ReplaceInput(1, |
| 1127 graph()->NewNode(simplified()->NumberAdd(), index, |
| 1128 jsgraph()->OneConstant())); |
| 1129 } |
| 1130 |
| 1131 // Compute the new {length}. |
| 1132 length = graph()->NewNode(simplified()->NumberSubtract(), length, |
| 1133 jsgraph()->OneConstant()); |
| 1134 |
| 1135 // Store the new {length} to the {receiver}. |
| 1136 etrue1 = graph()->NewNode( |
| 1137 simplified()->StoreField( |
| 1138 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), |
| 1139 receiver, length, etrue1, if_true1); |
| 1140 |
| 1141 // Store a hole to the element we just removed from the {receiver}. |
| 1142 etrue1 = graph()->NewNode( |
| 1143 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( |
| 1144 GetHoleyElementsKind(receiver_map->elements_kind()))), |
| 1145 elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1); |
| 1146 } |
| 1147 |
| 1148 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1149 Node* efalse1 = efalse0; |
| 1150 Node* vfalse1; |
| 1151 { |
| 1152 // Call the generic C++ implementation. |
| 1153 const int builtin_index = Builtins::kArrayShift; |
| 1154 CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor( |
| 1155 graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver, |
| 1156 Builtins::name(builtin_index), node->op()->properties(), |
| 1157 CallDescriptor::kNeedsFrameState); |
| 1158 Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs, |
| 1159 kArgvOnStack, true); |
| 1160 Address builtin_entry = Builtins::CppEntryOf(builtin_index); |
| 1161 Node* entry = jsgraph()->ExternalConstant( |
| 1162 ExternalReference(builtin_entry, isolate())); |
| 1163 Node* argc = |
| 1164 jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver); |
| 1165 if_false1 = efalse1 = vfalse1 = |
| 1166 graph()->NewNode(common()->Call(desc), stub_code, receiver, argc, |
| 1167 target, jsgraph()->UndefinedConstant(), entry, |
| 1168 argc, context, frame_state, efalse1, if_false1); |
| 1169 } |
| 1170 |
| 1171 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 1172 efalse0 = |
| 1173 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
| 1174 vfalse0 = |
| 1175 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 1176 vtrue1, vfalse1, if_false0); |
| 1177 } |
| 1178 |
| 1179 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1180 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1181 Node* value = |
| 1182 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 1183 vtrue0, vfalse0, control); |
| 1184 |
| 1185 // Convert the hole to undefined. Do this last, so that we can optimize |
| 1186 // conversion operator via some smart strength reduction in many cases. |
| 1187 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { |
| 1188 value = |
| 1189 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); |
| 1190 } |
| 1191 |
| 1192 ReplaceWithValue(node, value, effect, control); |
| 1193 return Replace(value); |
| 1194 } |
| 1195 return NoChange(); |
| 1196 } |
| 1197 |
1024 namespace { | 1198 namespace { |
1025 | 1199 |
1026 bool HasInstanceTypeWitness(Node* receiver, Node* effect, | 1200 bool HasInstanceTypeWitness(Node* receiver, Node* effect, |
1027 InstanceType instance_type) { | 1201 InstanceType instance_type) { |
1028 for (Node* dominator = effect;;) { | 1202 for (Node* dominator = effect;;) { |
1029 if (dominator->opcode() == IrOpcode::kCheckMaps && | 1203 if (dominator->opcode() == IrOpcode::kCheckMaps && |
1030 NodeProperties::IsSame(dominator->InputAt(0), receiver)) { | 1204 NodeProperties::IsSame(dominator->InputAt(0), receiver)) { |
1031 ZoneHandleSet<Map> const& maps = | 1205 ZoneHandleSet<Map> const& maps = |
1032 CheckMapsParametersOf(dominator->op()).maps(); | 1206 CheckMapsParametersOf(dominator->op()).maps(); |
1033 // Check if all maps have the given {instance_type}. | 1207 // Check if all maps have the given {instance_type}. |
(...skipping 1100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2134 case kArrayValues: | 2308 case kArrayValues: |
2135 return ReduceArrayIterator(node, IterationKind::kValues); | 2309 return ReduceArrayIterator(node, IterationKind::kValues); |
2136 case kArrayIteratorNext: | 2310 case kArrayIteratorNext: |
2137 return ReduceArrayIteratorNext(node); | 2311 return ReduceArrayIteratorNext(node); |
2138 case kArrayIsArray: | 2312 case kArrayIsArray: |
2139 return ReduceArrayIsArray(node); | 2313 return ReduceArrayIsArray(node); |
2140 case kArrayPop: | 2314 case kArrayPop: |
2141 return ReduceArrayPop(node); | 2315 return ReduceArrayPop(node); |
2142 case kArrayPush: | 2316 case kArrayPush: |
2143 return ReduceArrayPush(node); | 2317 return ReduceArrayPush(node); |
| 2318 case kArrayShift: |
| 2319 return ReduceArrayShift(node); |
2144 case kDateNow: | 2320 case kDateNow: |
2145 return ReduceDateNow(node); | 2321 return ReduceDateNow(node); |
2146 case kDateGetTime: | 2322 case kDateGetTime: |
2147 return ReduceDateGetTime(node); | 2323 return ReduceDateGetTime(node); |
2148 case kGlobalIsFinite: | 2324 case kGlobalIsFinite: |
2149 reduction = ReduceGlobalIsFinite(node); | 2325 reduction = ReduceGlobalIsFinite(node); |
2150 break; | 2326 break; |
2151 case kGlobalIsNaN: | 2327 case kGlobalIsNaN: |
2152 reduction = ReduceGlobalIsNaN(node); | 2328 reduction = ReduceGlobalIsNaN(node); |
2153 break; | 2329 break; |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2348 return jsgraph()->simplified(); | 2524 return jsgraph()->simplified(); |
2349 } | 2525 } |
2350 | 2526 |
2351 JSOperatorBuilder* JSBuiltinReducer::javascript() const { | 2527 JSOperatorBuilder* JSBuiltinReducer::javascript() const { |
2352 return jsgraph()->javascript(); | 2528 return jsgraph()->javascript(); |
2353 } | 2529 } |
2354 | 2530 |
2355 } // namespace compiler | 2531 } // namespace compiler |
2356 } // namespace internal | 2532 } // namespace internal |
2357 } // namespace v8 | 2533 } // namespace v8 |
OLD | NEW |