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 1372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1383 node->ReplaceInput(5, control); | 1383 node->ReplaceInput(5, control); |
1384 node->TrimInputCount(6); | 1384 node->TrimInputCount(6); |
1385 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access)); | 1385 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access)); |
1386 return Changed(node); | 1386 return Changed(node); |
1387 } | 1387 } |
1388 } | 1388 } |
1389 } | 1389 } |
1390 return NoChange(); | 1390 return NoChange(); |
1391 } | 1391 } |
1392 | 1392 |
| 1393 JSTypedLowering::InferHasInPrototypeChainResult |
| 1394 JSTypedLowering::InferHasInPrototypeChain(Node* receiver, Node* effect, |
| 1395 Handle<HeapObject> prototype) { |
| 1396 ZoneHandleSet<Map> receiver_maps; |
| 1397 NodeProperties::InferReceiverMapsResult result = |
| 1398 NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps); |
| 1399 if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain; |
| 1400 |
| 1401 // Check if either all or none of the {receiver_maps} have the given |
| 1402 // {prototype} in their prototype chain. |
| 1403 bool all = true; |
| 1404 bool none = true; |
| 1405 for (size_t i = 0; i < receiver_maps.size(); ++i) { |
| 1406 Handle<Map> receiver_map = receiver_maps[i]; |
| 1407 if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
| 1408 return kMayBeInPrototypeChain; |
| 1409 } |
| 1410 if (result == NodeProperties::kUnreliableReceiverMaps) { |
| 1411 // In case of an unreliable {result} we need to ensure that all |
| 1412 // {receiver_maps} are stable, because otherwise we cannot trust |
| 1413 // the {receiver_maps} information, since arbitrary side-effects |
| 1414 // may have happened. |
| 1415 if (!receiver_map->is_stable()) { |
| 1416 return kMayBeInPrototypeChain; |
| 1417 } |
| 1418 } |
| 1419 for (PrototypeIterator j(receiver_map);; j.Advance()) { |
| 1420 if (j.IsAtEnd()) { |
| 1421 all = false; |
| 1422 break; |
| 1423 } |
| 1424 Handle<HeapObject> const current = |
| 1425 PrototypeIterator::GetCurrent<HeapObject>(j); |
| 1426 if (current.is_identical_to(prototype)) { |
| 1427 none = false; |
| 1428 break; |
| 1429 } |
| 1430 if (!current->map()->is_stable() || |
| 1431 current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
| 1432 return kMayBeInPrototypeChain; |
| 1433 } |
| 1434 } |
| 1435 } |
| 1436 DCHECK_IMPLIES(all, !none); |
| 1437 DCHECK_IMPLIES(none, !all); |
| 1438 |
| 1439 if (all) return kIsInPrototypeChain; |
| 1440 if (none) return kIsNotInPrototypeChain; |
| 1441 return kMayBeInPrototypeChain; |
| 1442 } |
| 1443 |
| 1444 Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) { |
| 1445 DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode()); |
| 1446 Node* value = NodeProperties::GetValueInput(node, 0); |
| 1447 Type* value_type = NodeProperties::GetType(value); |
| 1448 Node* prototype = NodeProperties::GetValueInput(node, 1); |
| 1449 Type* prototype_type = NodeProperties::GetType(prototype); |
| 1450 Node* context = NodeProperties::GetContextInput(node); |
| 1451 Node* frame_state = NodeProperties::GetFrameStateInput(node); |
| 1452 Node* effect = NodeProperties::GetEffectInput(node); |
| 1453 Node* control = NodeProperties::GetControlInput(node); |
| 1454 |
| 1455 // If {value} cannot be a receiver, then it cannot have {prototype} in |
| 1456 // it's prototype chain (all Primitive values have a null prototype). |
| 1457 if (value_type->Is(Type::Primitive())) { |
| 1458 Node* value = jsgraph()->FalseConstant(); |
| 1459 ReplaceWithValue(node, value, effect, control); |
| 1460 return Replace(value); |
| 1461 } |
| 1462 |
| 1463 // Check if we can constant-fold the prototype chain walk |
| 1464 // for the given {value} and the {prototype}. |
| 1465 if (prototype_type->IsHeapConstant()) { |
| 1466 InferHasInPrototypeChainResult result = InferHasInPrototypeChain( |
| 1467 value, effect, prototype_type->AsHeapConstant()->Value()); |
| 1468 if (result != kMayBeInPrototypeChain) { |
| 1469 Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain); |
| 1470 ReplaceWithValue(node, value, effect, control); |
| 1471 return Replace(value); |
| 1472 } |
| 1473 } |
| 1474 |
| 1475 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
| 1476 Node* branch0 = |
| 1477 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); |
| 1478 |
| 1479 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1480 Node* etrue0 = effect; |
| 1481 Node* vtrue0 = jsgraph()->FalseConstant(); |
| 1482 |
| 1483 control = graph()->NewNode(common()->IfFalse(), branch0); |
| 1484 |
| 1485 // Loop through the {value}s prototype chain looking for the {prototype}. |
| 1486 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); |
| 1487 Node* eloop = effect = |
| 1488 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); |
| 1489 Node* vloop = value = graph()->NewNode( |
| 1490 common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop); |
| 1491 NodeProperties::SetType(vloop, Type::NonInternal()); |
| 1492 |
| 1493 // Load the {value} map and instance type. |
| 1494 Node* value_map = effect = graph()->NewNode( |
| 1495 simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); |
| 1496 Node* value_instance_type = effect = graph()->NewNode( |
| 1497 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map, |
| 1498 effect, control); |
| 1499 |
| 1500 // Check if the {value} is a special receiver, because for special |
| 1501 // receivers, i.e. proxies or API values that need access checks, |
| 1502 // we have to use the %HasInPrototypeChain runtime function instead. |
| 1503 Node* check1 = graph()->NewNode( |
| 1504 simplified()->NumberLessThanOrEqual(), value_instance_type, |
| 1505 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); |
| 1506 Node* branch1 = |
| 1507 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); |
| 1508 |
| 1509 control = graph()->NewNode(common()->IfFalse(), branch1); |
| 1510 |
| 1511 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1512 Node* etrue1 = effect; |
| 1513 Node* vtrue1; |
| 1514 |
| 1515 // Check if the {value} is not a receiver at all. |
| 1516 Node* check10 = |
| 1517 graph()->NewNode(simplified()->NumberLessThan(), value_instance_type, |
| 1518 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); |
| 1519 Node* branch10 = |
| 1520 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); |
| 1521 |
| 1522 // A primitive value cannot match the {prototype} we're looking for. |
| 1523 if_true1 = graph()->NewNode(common()->IfTrue(), branch10); |
| 1524 vtrue1 = jsgraph()->FalseConstant(); |
| 1525 |
| 1526 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); |
| 1527 Node* efalse1 = etrue1; |
| 1528 Node* vfalse1; |
| 1529 { |
| 1530 // Slow path, need to call the %HasInPrototypeChain runtime function. |
| 1531 vfalse1 = efalse1 = if_false1 = graph()->NewNode( |
| 1532 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), value, |
| 1533 prototype, context, frame_state, efalse1, if_false1); |
| 1534 |
| 1535 // Replace any potential {IfException} uses of {node} to catch |
| 1536 // exceptions from this %HasInPrototypeChain runtime call instead. |
| 1537 Node* on_exception = nullptr; |
| 1538 if (NodeProperties::IsExceptionalCall(node, &on_exception)) { |
| 1539 NodeProperties::ReplaceControlInput(on_exception, vfalse1); |
| 1540 NodeProperties::ReplaceEffectInput(on_exception, efalse1); |
| 1541 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); |
| 1542 Revisit(on_exception); |
| 1543 } |
| 1544 } |
| 1545 |
| 1546 // Load the {value} prototype. |
| 1547 Node* value_prototype = effect = graph()->NewNode( |
| 1548 simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map, |
| 1549 effect, control); |
| 1550 |
| 1551 // Check if we reached the end of {value}s prototype chain. |
| 1552 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), |
| 1553 value_prototype, jsgraph()->NullConstant()); |
| 1554 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); |
| 1555 |
| 1556 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 1557 Node* etrue2 = effect; |
| 1558 Node* vtrue2 = jsgraph()->FalseConstant(); |
| 1559 |
| 1560 control = graph()->NewNode(common()->IfFalse(), branch2); |
| 1561 |
| 1562 // Check if we reached the {prototype}. |
| 1563 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), |
| 1564 value_prototype, prototype); |
| 1565 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); |
| 1566 |
| 1567 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); |
| 1568 Node* etrue3 = effect; |
| 1569 Node* vtrue3 = jsgraph()->TrueConstant(); |
| 1570 |
| 1571 control = graph()->NewNode(common()->IfFalse(), branch3); |
| 1572 |
| 1573 // Close the loop. |
| 1574 vloop->ReplaceInput(1, value_prototype); |
| 1575 eloop->ReplaceInput(1, effect); |
| 1576 loop->ReplaceInput(1, control); |
| 1577 |
| 1578 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, |
| 1579 if_true3, if_false1); |
| 1580 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, |
| 1581 etrue3, efalse1, control); |
| 1582 |
| 1583 // Morph the {node} into an appropriate Phi. |
| 1584 ReplaceWithValue(node, node, effect, control); |
| 1585 node->ReplaceInput(0, vtrue0); |
| 1586 node->ReplaceInput(1, vtrue1); |
| 1587 node->ReplaceInput(2, vtrue2); |
| 1588 node->ReplaceInput(3, vtrue3); |
| 1589 node->ReplaceInput(4, vfalse1); |
| 1590 node->ReplaceInput(5, control); |
| 1591 node->TrimInputCount(6); |
| 1592 NodeProperties::ChangeOp(node, |
| 1593 common()->Phi(MachineRepresentation::kTagged, 5)); |
| 1594 return Changed(node); |
| 1595 } |
| 1596 |
1393 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { | 1597 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { |
1394 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); | 1598 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); |
1395 Node* constructor = NodeProperties::GetValueInput(node, 0); | 1599 Node* constructor = NodeProperties::GetValueInput(node, 0); |
1396 Type* constructor_type = NodeProperties::GetType(constructor); | 1600 Type* constructor_type = NodeProperties::GetType(constructor); |
1397 Node* object = NodeProperties::GetValueInput(node, 1); | 1601 Node* object = NodeProperties::GetValueInput(node, 1); |
1398 Type* object_type = NodeProperties::GetType(object); | 1602 Type* object_type = NodeProperties::GetType(object); |
1399 | 1603 |
1400 // Check if the {constructor} cannot be callable. | 1604 // Check if the {constructor} cannot be callable. |
1401 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. | 1605 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. |
1402 if (!constructor_type->Maybe(Type::Callable())) { | 1606 if (!constructor_type->Maybe(Type::Callable())) { |
(...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2240 return ReduceUI32Shift(node, kSigned); | 2444 return ReduceUI32Shift(node, kSigned); |
2241 case IrOpcode::kJSShiftRightLogical: | 2445 case IrOpcode::kJSShiftRightLogical: |
2242 return ReduceUI32Shift(node, kUnsigned); | 2446 return ReduceUI32Shift(node, kUnsigned); |
2243 case IrOpcode::kJSAdd: | 2447 case IrOpcode::kJSAdd: |
2244 return ReduceJSAdd(node); | 2448 return ReduceJSAdd(node); |
2245 case IrOpcode::kJSSubtract: | 2449 case IrOpcode::kJSSubtract: |
2246 case IrOpcode::kJSMultiply: | 2450 case IrOpcode::kJSMultiply: |
2247 case IrOpcode::kJSDivide: | 2451 case IrOpcode::kJSDivide: |
2248 case IrOpcode::kJSModulus: | 2452 case IrOpcode::kJSModulus: |
2249 return ReduceNumberBinop(node); | 2453 return ReduceNumberBinop(node); |
| 2454 case IrOpcode::kJSHasInPrototypeChain: |
| 2455 return ReduceJSHasInPrototypeChain(node); |
2250 case IrOpcode::kJSOrdinaryHasInstance: | 2456 case IrOpcode::kJSOrdinaryHasInstance: |
2251 return ReduceJSOrdinaryHasInstance(node); | 2457 return ReduceJSOrdinaryHasInstance(node); |
2252 case IrOpcode::kJSToBoolean: | 2458 case IrOpcode::kJSToBoolean: |
2253 return ReduceJSToBoolean(node); | 2459 return ReduceJSToBoolean(node); |
2254 case IrOpcode::kJSToInteger: | 2460 case IrOpcode::kJSToInteger: |
2255 return ReduceJSToInteger(node); | 2461 return ReduceJSToInteger(node); |
2256 case IrOpcode::kJSToLength: | 2462 case IrOpcode::kJSToLength: |
2257 return ReduceJSToLength(node); | 2463 return ReduceJSToLength(node); |
2258 case IrOpcode::kJSToName: | 2464 case IrOpcode::kJSToName: |
2259 return ReduceJSToName(node); | 2465 return ReduceJSToName(node); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2346 } | 2552 } |
2347 | 2553 |
2348 | 2554 |
2349 CompilationDependencies* JSTypedLowering::dependencies() const { | 2555 CompilationDependencies* JSTypedLowering::dependencies() const { |
2350 return dependencies_; | 2556 return dependencies_; |
2351 } | 2557 } |
2352 | 2558 |
2353 } // namespace compiler | 2559 } // namespace compiler |
2354 } // namespace internal | 2560 } // namespace internal |
2355 } // namespace v8 | 2561 } // namespace v8 |
OLD | NEW |