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 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1074 node->ReplaceInput(0, a.allocation()); | 1074 node->ReplaceInput(0, a.allocation()); |
1075 node->ReplaceInput(1, a.effect()); | 1075 node->ReplaceInput(1, a.effect()); |
1076 node->set_op(common()->Finish(1)); | 1076 node->set_op(common()->Finish(1)); |
1077 node->TrimInputCount(2); | 1077 node->TrimInputCount(2); |
1078 return Changed(node); | 1078 return Changed(node); |
1079 } | 1079 } |
1080 return NoChange(); | 1080 return NoChange(); |
1081 } | 1081 } |
1082 | 1082 |
1083 | 1083 |
| 1084 Reduction JSTypedLowering::ReduceJSForInDone(Node* node) { |
| 1085 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode()); |
| 1086 node->set_op(machine()->Word32Equal()); |
| 1087 node->TrimInputCount(2); |
| 1088 return Changed(node); |
| 1089 } |
| 1090 |
| 1091 |
| 1092 Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) { |
| 1093 DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode()); |
| 1094 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 1095 Node* context = NodeProperties::GetContextInput(node); |
| 1096 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 1097 Node* effect = NodeProperties::GetEffectInput(node); |
| 1098 Node* control = NodeProperties::GetControlInput(node); |
| 1099 |
| 1100 // Get the set of properties to enumerate. |
| 1101 Node* cache_type = effect = graph()->NewNode( |
| 1102 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), receiver, |
| 1103 context, frame_state, effect, control); |
| 1104 control = graph()->NewNode(common()->IfSuccess(), cache_type); |
| 1105 |
| 1106 Node* receiver_map = effect = |
| 1107 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1108 receiver, effect, control); |
| 1109 Node* cache_type_map = effect = |
| 1110 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1111 cache_type, effect, control); |
| 1112 Node* meta_map = jsgraph()->HeapConstant(factory()->meta_map()); |
| 1113 |
| 1114 // If we got a map from the GetPropertyNamesFast runtime call, we can do a |
| 1115 // fast modification check. Otherwise, we got a fixed array, and we have to |
| 1116 // perform a slow check on every iteration. |
| 1117 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
| 1118 cache_type_map, meta_map); |
| 1119 Node* branch0 = |
| 1120 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 1121 |
| 1122 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1123 Node* cache_array_true0; |
| 1124 Node* cache_length_true0; |
| 1125 Node* cache_type_true0; |
| 1126 Node* etrue0; |
| 1127 { |
| 1128 // Enum cache case. |
| 1129 Node* cache_type_enum_length = etrue0 = graph()->NewNode( |
| 1130 simplified()->LoadField(AccessBuilder::ForMapBitField3()), cache_type, |
| 1131 effect, if_true0); |
| 1132 cache_length_true0 = |
| 1133 graph()->NewNode(machine()->Word32And(), cache_type_enum_length, |
| 1134 jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask)); |
| 1135 |
| 1136 Node* check1 = |
| 1137 graph()->NewNode(machine()->Word32Equal(), cache_length_true0, |
| 1138 jsgraph()->Int32Constant(0)); |
| 1139 Node* branch1 = |
| 1140 graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
| 1141 |
| 1142 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1143 Node* cache_array_true1; |
| 1144 Node* etrue1; |
| 1145 { |
| 1146 // No properties to enumerate. |
| 1147 cache_array_true1 = |
| 1148 jsgraph()->HeapConstant(factory()->empty_fixed_array()); |
| 1149 etrue1 = etrue0; |
| 1150 } |
| 1151 |
| 1152 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1153 Node* cache_array_false1; |
| 1154 Node* efalse1; |
| 1155 { |
| 1156 // Load the enumeration cache from the instance descriptors of {receiver}. |
| 1157 Node* receiver_map_descriptors = efalse1 = graph()->NewNode( |
| 1158 simplified()->LoadField(AccessBuilder::ForMapDescriptors()), |
| 1159 receiver_map, etrue0, if_false1); |
| 1160 Node* object_map_enum_cache = efalse1 = graph()->NewNode( |
| 1161 simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()), |
| 1162 receiver_map_descriptors, efalse1, if_false1); |
| 1163 cache_array_false1 = efalse1 = graph()->NewNode( |
| 1164 simplified()->LoadField( |
| 1165 AccessBuilder::ForDescriptorArrayEnumCacheBridgeCache()), |
| 1166 object_map_enum_cache, efalse1, if_false1); |
| 1167 } |
| 1168 |
| 1169 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 1170 etrue0 = |
| 1171 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
| 1172 cache_array_true0 = |
| 1173 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true1, |
| 1174 cache_array_false1, if_true0); |
| 1175 |
| 1176 cache_type_true0 = cache_type; |
| 1177 } |
| 1178 |
| 1179 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1180 Node* cache_array_false0; |
| 1181 Node* cache_length_false0; |
| 1182 Node* cache_type_false0; |
| 1183 Node* efalse0; |
| 1184 { |
| 1185 // FixedArray case. |
| 1186 Node* receiver_instance_type = efalse0 = graph()->NewNode( |
| 1187 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |
| 1188 receiver_map, effect, if_false0); |
| 1189 |
| 1190 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1191 cache_type_false0 = graph()->NewNode( |
| 1192 common()->Select(kMachAnyTagged, BranchHint::kFalse), |
| 1193 graph()->NewNode(machine()->Uint32LessThanOrEqual(), |
| 1194 receiver_instance_type, |
| 1195 jsgraph()->Uint32Constant(LAST_JS_PROXY_TYPE)), |
| 1196 jsgraph()->ZeroConstant(), // Zero indicagtes proxy. |
| 1197 jsgraph()->OneConstant()); // One means slow check. |
| 1198 |
| 1199 cache_array_false0 = cache_type; |
| 1200 cache_length_false0 = efalse0 = graph()->NewNode( |
| 1201 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), |
| 1202 cache_array_false0, efalse0, if_false0); |
| 1203 } |
| 1204 |
| 1205 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1206 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1207 Node* cache_array = |
| 1208 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true0, |
| 1209 cache_array_false0, control); |
| 1210 Node* cache_length = |
| 1211 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_length_true0, |
| 1212 cache_length_false0, control); |
| 1213 cache_type = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), |
| 1214 cache_type_true0, cache_type_false0, control); |
| 1215 |
| 1216 for (auto edge : node->use_edges()) { |
| 1217 Node* const use = edge.from(); |
| 1218 if (NodeProperties::IsEffectEdge(edge)) { |
| 1219 edge.UpdateTo(effect); |
| 1220 Revisit(use); |
| 1221 } else { |
| 1222 if (NodeProperties::IsControlEdge(edge)) { |
| 1223 DCHECK_EQ(IrOpcode::kIfSuccess, use->opcode()); |
| 1224 Replace(use, control); |
| 1225 } else { |
| 1226 DCHECK(NodeProperties::IsValueEdge(edge)); |
| 1227 DCHECK_EQ(IrOpcode::kProjection, use->opcode()); |
| 1228 switch (ProjectionIndexOf(use->op())) { |
| 1229 case 0: |
| 1230 Replace(use, cache_type); |
| 1231 break; |
| 1232 case 1: |
| 1233 Replace(use, cache_array); |
| 1234 break; |
| 1235 case 2: |
| 1236 Replace(use, cache_length); |
| 1237 break; |
| 1238 default: |
| 1239 UNREACHABLE(); |
| 1240 break; |
| 1241 } |
| 1242 } |
| 1243 use->Kill(); |
| 1244 } |
| 1245 } |
| 1246 return NoChange(); // All uses were replaced already above. |
| 1247 } |
| 1248 |
| 1249 |
| 1250 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { |
| 1251 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode()); |
| 1252 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 1253 Node* cache_array = NodeProperties::GetValueInput(node, 1); |
| 1254 Node* cache_type = NodeProperties::GetValueInput(node, 2); |
| 1255 Node* index = NodeProperties::GetValueInput(node, 3); |
| 1256 Node* context = NodeProperties::GetContextInput(node); |
| 1257 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 1258 Node* effect = NodeProperties::GetEffectInput(node); |
| 1259 Node* control = NodeProperties::GetControlInput(node); |
| 1260 |
| 1261 // Load the next {key} from the {cache_array}. |
| 1262 Node* key = effect = graph()->NewNode( |
| 1263 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), |
| 1264 cache_array, index, effect, control); |
| 1265 |
| 1266 // Load the map of the {receiver}. |
| 1267 Node* receiver_map = effect = |
| 1268 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1269 receiver, effect, control); |
| 1270 |
| 1271 // Check if the expected map still matches that of the {receiver}. |
| 1272 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
| 1273 receiver_map, cache_type); |
| 1274 Node* branch0 = |
| 1275 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 1276 |
| 1277 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1278 Node* etrue0; |
| 1279 Node* vtrue0; |
| 1280 { |
| 1281 // Don't need filtering since expected map still matches that of the |
| 1282 // {receiver}. |
| 1283 etrue0 = effect; |
| 1284 vtrue0 = key; |
| 1285 } |
| 1286 |
| 1287 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1288 Node* efalse0; |
| 1289 Node* vfalse0; |
| 1290 { |
| 1291 // Check if the {cache_type} is zero, which indicates proxy. |
| 1292 Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
| 1293 cache_type, jsgraph()->ZeroConstant()); |
| 1294 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1295 check1, if_false0); |
| 1296 |
| 1297 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1298 Node* etrue1; |
| 1299 Node* vtrue1; |
| 1300 { |
| 1301 // Don't do filtering for proxies. |
| 1302 etrue1 = effect; |
| 1303 vtrue1 = key; |
| 1304 } |
| 1305 |
| 1306 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1307 Node* efalse1; |
| 1308 Node* vfalse1; |
| 1309 { |
| 1310 // Filter the {key} to check if it's still a valid property of the |
| 1311 // {receiver} (does the ToName conversion implicitly). |
| 1312 vfalse1 = efalse1 = graph()->NewNode( |
| 1313 javascript()->CallRuntime(Runtime::kForInFilter, 2), receiver, key, |
| 1314 context, frame_state, effect, if_false1); |
| 1315 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); |
| 1316 } |
| 1317 |
| 1318 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 1319 efalse0 = |
| 1320 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
| 1321 vfalse0 = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue1, |
| 1322 vfalse1, if_false0); |
| 1323 } |
| 1324 |
| 1325 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1326 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1327 ReplaceWithValue(node, node, effect, control); |
| 1328 node->set_op(common()->Phi(kMachAnyTagged, 2)); |
| 1329 node->ReplaceInput(0, vtrue0); |
| 1330 node->ReplaceInput(1, vfalse0); |
| 1331 node->ReplaceInput(2, control); |
| 1332 node->TrimInputCount(3); |
| 1333 return Changed(node); |
| 1334 } |
| 1335 |
| 1336 |
| 1337 Reduction JSTypedLowering::ReduceJSForInStep(Node* node) { |
| 1338 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode()); |
| 1339 node->set_op(machine()->Int32Add()); |
| 1340 node->ReplaceInput(1, jsgraph()->Int32Constant(1)); |
| 1341 DCHECK_EQ(2, node->InputCount()); |
| 1342 return Changed(node); |
| 1343 } |
| 1344 |
| 1345 |
1084 Reduction JSTypedLowering::Reduce(Node* node) { | 1346 Reduction JSTypedLowering::Reduce(Node* node) { |
1085 // Check if the output type is a singleton. In that case we already know the | 1347 // Check if the output type is a singleton. In that case we already know the |
1086 // result value and can simply replace the node if it's eliminable. | 1348 // result value and can simply replace the node if it's eliminable. |
1087 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && | 1349 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && |
1088 node->op()->HasProperty(Operator::kEliminatable)) { | 1350 node->op()->HasProperty(Operator::kEliminatable)) { |
1089 Type* upper = NodeProperties::GetBounds(node).upper; | 1351 Type* upper = NodeProperties::GetBounds(node).upper; |
1090 if (upper->IsConstant()) { | 1352 if (upper->IsConstant()) { |
1091 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); | 1353 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); |
1092 ReplaceWithValue(node, replacement); | 1354 ReplaceWithValue(node, replacement); |
1093 return Changed(replacement); | 1355 return Changed(replacement); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1170 case IrOpcode::kJSCreateClosure: | 1432 case IrOpcode::kJSCreateClosure: |
1171 return ReduceJSCreateClosure(node); | 1433 return ReduceJSCreateClosure(node); |
1172 case IrOpcode::kJSCreateLiteralArray: | 1434 case IrOpcode::kJSCreateLiteralArray: |
1173 return ReduceJSCreateLiteralArray(node); | 1435 return ReduceJSCreateLiteralArray(node); |
1174 case IrOpcode::kJSCreateLiteralObject: | 1436 case IrOpcode::kJSCreateLiteralObject: |
1175 return ReduceJSCreateLiteralObject(node); | 1437 return ReduceJSCreateLiteralObject(node); |
1176 case IrOpcode::kJSCreateWithContext: | 1438 case IrOpcode::kJSCreateWithContext: |
1177 return ReduceJSCreateWithContext(node); | 1439 return ReduceJSCreateWithContext(node); |
1178 case IrOpcode::kJSCreateBlockContext: | 1440 case IrOpcode::kJSCreateBlockContext: |
1179 return ReduceJSCreateBlockContext(node); | 1441 return ReduceJSCreateBlockContext(node); |
| 1442 case IrOpcode::kJSForInDone: |
| 1443 return ReduceJSForInDone(node); |
| 1444 case IrOpcode::kJSForInNext: |
| 1445 return ReduceJSForInNext(node); |
| 1446 case IrOpcode::kJSForInPrepare: |
| 1447 return ReduceJSForInPrepare(node); |
| 1448 case IrOpcode::kJSForInStep: |
| 1449 return ReduceJSForInStep(node); |
1180 default: | 1450 default: |
1181 break; | 1451 break; |
1182 } | 1452 } |
1183 return NoChange(); | 1453 return NoChange(); |
1184 } | 1454 } |
1185 | 1455 |
1186 | 1456 |
1187 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { | 1457 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
1188 if (rhs == 0) return lhs; | 1458 if (rhs == 0) return lhs; |
1189 return graph()->NewNode(machine()->Word32Shl(), lhs, | 1459 return graph()->NewNode(machine()->Word32Shl(), lhs, |
(...skipping 17 matching lines...) Expand all Loading... |
1207 } | 1477 } |
1208 | 1478 |
1209 | 1479 |
1210 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1480 MachineOperatorBuilder* JSTypedLowering::machine() const { |
1211 return jsgraph()->machine(); | 1481 return jsgraph()->machine(); |
1212 } | 1482 } |
1213 | 1483 |
1214 } // namespace compiler | 1484 } // namespace compiler |
1215 } // namespace internal | 1485 } // namespace internal |
1216 } // namespace v8 | 1486 } // namespace v8 |
OLD | NEW |