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

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

Issue 2934893002: [builtins] Properly optimize Object.prototype.isPrototypeOf. (Closed)
Patch Set: Created 3 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') | src/compiler/opcodes.h » ('j') | 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/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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698