| 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-typed-lowering.h" | 5 #include "src/compiler/js-typed-lowering.h" |
| 6 | 6 |
| 7 #include "src/ast/modules.h" | 7 #include "src/ast/modules.h" |
| 8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.h" |
| 9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
| 10 #include "src/compilation-dependencies.h" | 10 #include "src/compilation-dependencies.h" |
| (...skipping 1308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 } | 1319 } |
| 1320 return NoChange(); | 1320 return NoChange(); |
| 1321 } | 1321 } |
| 1322 | 1322 |
| 1323 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { | 1323 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { |
| 1324 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); | 1324 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); |
| 1325 Node* constructor = NodeProperties::GetValueInput(node, 0); | 1325 Node* constructor = NodeProperties::GetValueInput(node, 0); |
| 1326 Type* constructor_type = NodeProperties::GetType(constructor); | 1326 Type* constructor_type = NodeProperties::GetType(constructor); |
| 1327 Node* object = NodeProperties::GetValueInput(node, 1); | 1327 Node* object = NodeProperties::GetValueInput(node, 1); |
| 1328 Type* object_type = NodeProperties::GetType(object); | 1328 Type* object_type = NodeProperties::GetType(object); |
| 1329 Node* context = NodeProperties::GetContextInput(node); | |
| 1330 Node* frame_state = NodeProperties::GetFrameStateInput(node); | |
| 1331 Node* effect = NodeProperties::GetEffectInput(node); | |
| 1332 Node* control = NodeProperties::GetControlInput(node); | |
| 1333 | 1329 |
| 1334 // Check if the {constructor} cannot be callable. | 1330 // Check if the {constructor} cannot be callable. |
| 1335 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. | 1331 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. |
| 1336 if (!constructor_type->Maybe(Type::Callable())) { | 1332 if (!constructor_type->Maybe(Type::Callable())) { |
| 1337 Node* value = jsgraph()->FalseConstant(); | 1333 Node* value = jsgraph()->FalseConstant(); |
| 1338 ReplaceWithValue(node, value, effect, control); | 1334 ReplaceWithValue(node, value); |
| 1339 return Replace(value); | 1335 return Replace(value); |
| 1340 } | 1336 } |
| 1341 | 1337 |
| 1342 // If the {constructor} cannot be a JSBoundFunction and then {object} | 1338 // If the {constructor} cannot be a JSBoundFunction and then {object} |
| 1343 // cannot be a JSReceiver, then this can be constant-folded to false. | 1339 // cannot be a JSReceiver, then this can be constant-folded to false. |
| 1344 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3. | 1340 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3. |
| 1345 if (!object_type->Maybe(Type::Receiver()) && | 1341 if (!object_type->Maybe(Type::Receiver()) && |
| 1346 !constructor_type->Maybe(Type::BoundFunction())) { | 1342 !constructor_type->Maybe(Type::BoundFunction())) { |
| 1347 Node* value = jsgraph()->FalseConstant(); | 1343 Node* value = jsgraph()->FalseConstant(); |
| 1348 ReplaceWithValue(node, value, effect, control); | 1344 ReplaceWithValue(node, value); |
| 1349 return Replace(value); | 1345 return Replace(value); |
| 1350 } | 1346 } |
| 1351 | 1347 |
| 1352 // Check if the {constructor} is a (known) JSFunction. | 1348 return NoChange(); |
| 1353 if (!constructor_type->IsHeapConstant() || | |
| 1354 !constructor_type->AsHeapConstant()->Value()->IsJSFunction()) { | |
| 1355 return NoChange(); | |
| 1356 } | |
| 1357 Handle<JSFunction> function = | |
| 1358 Handle<JSFunction>::cast(constructor_type->AsHeapConstant()->Value()); | |
| 1359 | |
| 1360 // Check if the {function} already has an initial map (i.e. the | |
| 1361 // {function} has been used as a constructor at least once). | |
| 1362 if (!function->has_initial_map()) return NoChange(); | |
| 1363 | |
| 1364 // Check if the {function}s "prototype" is a JSReceiver. | |
| 1365 if (!function->prototype()->IsJSReceiver()) return NoChange(); | |
| 1366 | |
| 1367 // Install a code dependency on the {function}s initial map. | |
| 1368 Handle<Map> initial_map(function->initial_map(), isolate()); | |
| 1369 dependencies()->AssumeInitialMapCantChange(initial_map); | |
| 1370 | |
| 1371 Node* prototype = | |
| 1372 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); | |
| 1373 | |
| 1374 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object); | |
| 1375 Node* branch0 = | |
| 1376 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | |
| 1377 | |
| 1378 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | |
| 1379 Node* etrue0 = effect; | |
| 1380 Node* vtrue0 = jsgraph()->FalseConstant(); | |
| 1381 | |
| 1382 control = graph()->NewNode(common()->IfFalse(), branch0); | |
| 1383 | |
| 1384 // Loop through the {object}s prototype chain looking for the {prototype}. | |
| 1385 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); | |
| 1386 Node* eloop = effect = | |
| 1387 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); | |
| 1388 Node* vloop = object = graph()->NewNode( | |
| 1389 common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop); | |
| 1390 // TODO(jarin): This is a very ugly hack to work-around the super-smart | |
| 1391 // implicit typing of the Phi, which goes completely nuts if the {object} | |
| 1392 // is for example a HeapConstant. | |
| 1393 NodeProperties::SetType(vloop, Type::NonInternal()); | |
| 1394 | |
| 1395 // Load the {object} map and instance type. | |
| 1396 Node* object_map = effect = | |
| 1397 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, | |
| 1398 effect, control); | |
| 1399 Node* object_instance_type = effect = graph()->NewNode( | |
| 1400 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map, | |
| 1401 effect, control); | |
| 1402 | |
| 1403 // Check if the {object} is a special receiver, because for special | |
| 1404 // receivers, i.e. proxies or API objects that need access checks, | |
| 1405 // we have to use the %HasInPrototypeChain runtime function instead. | |
| 1406 Node* check1 = graph()->NewNode( | |
| 1407 simplified()->NumberLessThanOrEqual(), object_instance_type, | |
| 1408 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); | |
| 1409 Node* branch1 = | |
| 1410 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); | |
| 1411 | |
| 1412 control = graph()->NewNode(common()->IfFalse(), branch1); | |
| 1413 | |
| 1414 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | |
| 1415 Node* etrue1 = effect; | |
| 1416 Node* vtrue1; | |
| 1417 | |
| 1418 // Check if the {object} is not a receiver at all. | |
| 1419 Node* check10 = | |
| 1420 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type, | |
| 1421 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); | |
| 1422 Node* branch10 = | |
| 1423 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); | |
| 1424 | |
| 1425 // A primitive value cannot match the {prototype} we're looking for. | |
| 1426 if_true1 = graph()->NewNode(common()->IfTrue(), branch10); | |
| 1427 vtrue1 = jsgraph()->FalseConstant(); | |
| 1428 | |
| 1429 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); | |
| 1430 Node* efalse1 = etrue1; | |
| 1431 Node* vfalse1; | |
| 1432 { | |
| 1433 // Slow path, need to call the %HasInPrototypeChain runtime function. | |
| 1434 vfalse1 = efalse1 = if_false1 = graph()->NewNode( | |
| 1435 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object, | |
| 1436 prototype, context, frame_state, efalse1, if_false1); | |
| 1437 | |
| 1438 // Replace any potential {IfException} uses of {node} to catch exceptions | |
| 1439 // from this %HasInPrototypeChain runtime call instead. | |
| 1440 Node* on_exception = nullptr; | |
| 1441 if (NodeProperties::IsExceptionalCall(node, &on_exception)) { | |
| 1442 NodeProperties::ReplaceControlInput(on_exception, vfalse1); | |
| 1443 NodeProperties::ReplaceEffectInput(on_exception, efalse1); | |
| 1444 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); | |
| 1445 Revisit(on_exception); | |
| 1446 } | |
| 1447 } | |
| 1448 | |
| 1449 // Load the {object} prototype. | |
| 1450 Node* object_prototype = effect = graph()->NewNode( | |
| 1451 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map, | |
| 1452 effect, control); | |
| 1453 | |
| 1454 // Check if we reached the end of {object}s prototype chain. | |
| 1455 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), | |
| 1456 object_prototype, jsgraph()->NullConstant()); | |
| 1457 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); | |
| 1458 | |
| 1459 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); | |
| 1460 Node* etrue2 = effect; | |
| 1461 Node* vtrue2 = jsgraph()->FalseConstant(); | |
| 1462 | |
| 1463 control = graph()->NewNode(common()->IfFalse(), branch2); | |
| 1464 | |
| 1465 // Check if we reached the {prototype}. | |
| 1466 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), | |
| 1467 object_prototype, prototype); | |
| 1468 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); | |
| 1469 | |
| 1470 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); | |
| 1471 Node* etrue3 = effect; | |
| 1472 Node* vtrue3 = jsgraph()->TrueConstant(); | |
| 1473 | |
| 1474 control = graph()->NewNode(common()->IfFalse(), branch3); | |
| 1475 | |
| 1476 // Close the loop. | |
| 1477 vloop->ReplaceInput(1, object_prototype); | |
| 1478 eloop->ReplaceInput(1, effect); | |
| 1479 loop->ReplaceInput(1, control); | |
| 1480 | |
| 1481 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, | |
| 1482 if_true3, if_false1); | |
| 1483 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, | |
| 1484 etrue3, efalse1, control); | |
| 1485 | |
| 1486 // Morph the {node} into an appropriate Phi. | |
| 1487 ReplaceWithValue(node, node, effect, control); | |
| 1488 node->ReplaceInput(0, vtrue0); | |
| 1489 node->ReplaceInput(1, vtrue1); | |
| 1490 node->ReplaceInput(2, vtrue2); | |
| 1491 node->ReplaceInput(3, vtrue3); | |
| 1492 node->ReplaceInput(4, vfalse1); | |
| 1493 node->ReplaceInput(5, control); | |
| 1494 node->TrimInputCount(6); | |
| 1495 NodeProperties::ChangeOp(node, | |
| 1496 common()->Phi(MachineRepresentation::kTagged, 5)); | |
| 1497 return Changed(node); | |
| 1498 } | 1349 } |
| 1499 | 1350 |
| 1500 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { | 1351 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { |
| 1501 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); | 1352 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); |
| 1502 ContextAccess const& access = ContextAccessOf(node->op()); | 1353 ContextAccess const& access = ContextAccessOf(node->op()); |
| 1503 Node* effect = NodeProperties::GetEffectInput(node); | 1354 Node* effect = NodeProperties::GetEffectInput(node); |
| 1504 Node* context = NodeProperties::GetContextInput(node); | 1355 Node* context = NodeProperties::GetContextInput(node); |
| 1505 Node* control = graph()->start(); | 1356 Node* control = graph()->start(); |
| 1506 for (size_t i = 0; i < access.depth(); ++i) { | 1357 for (size_t i = 0; i < access.depth(); ++i) { |
| 1507 context = effect = graph()->NewNode( | 1358 context = effect = graph()->NewNode( |
| (...skipping 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 } | 2241 } |
| 2391 | 2242 |
| 2392 | 2243 |
| 2393 CompilationDependencies* JSTypedLowering::dependencies() const { | 2244 CompilationDependencies* JSTypedLowering::dependencies() const { |
| 2394 return dependencies_; | 2245 return dependencies_; |
| 2395 } | 2246 } |
| 2396 | 2247 |
| 2397 } // namespace compiler | 2248 } // namespace compiler |
| 2398 } // namespace internal | 2249 } // namespace internal |
| 2399 } // namespace v8 | 2250 } // namespace v8 |
| OLD | NEW |