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, | |
Benedikt Meurer
2017/06/12 19:52:26
Moved here from JSNativeContextSpecialization.
| |
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) { | |
Benedikt Meurer
2017/06/12 19:52:26
Moved here from JSNativeContextSpecialization::Red
| |
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 |