Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 1155313008: [turbofan] First steps towards optimizing for-in loops. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698