OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 | 7 |
8 namespace v8 { | 8 namespace v8 { |
9 namespace internal { | 9 namespace internal { |
10 | 10 |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1409 Branch(Int32LessThan(index, SmiToWord32(length)), &if_iskeyinrange, | 1409 Branch(Int32LessThan(index, SmiToWord32(length)), &if_iskeyinrange, |
1410 if_not_found); | 1410 if_not_found); |
1411 | 1411 |
1412 Bind(&if_iskeyinrange); | 1412 Bind(&if_iskeyinrange); |
1413 Node* element = LoadFixedArrayElementInt32Index(elements, index); | 1413 Node* element = LoadFixedArrayElementInt32Index(elements, index); |
1414 Node* the_hole = LoadRoot(Heap::kTheHoleValueRootIndex); | 1414 Node* the_hole = LoadRoot(Heap::kTheHoleValueRootIndex); |
1415 Branch(WordEqual(element, the_hole), if_not_found, if_found); | 1415 Branch(WordEqual(element, the_hole), if_not_found, if_found); |
1416 } | 1416 } |
1417 } | 1417 } |
1418 | 1418 |
| 1419 Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, |
| 1420 Node* object) { |
| 1421 Variable var_result(this, MachineRepresentation::kTagged); |
| 1422 Label return_false(this), return_true(this), |
| 1423 return_runtime(this, Label::kDeferred), return_result(this); |
| 1424 |
| 1425 // Goto runtime if {object} is a Smi. |
| 1426 GotoIf(WordIsSmi(object), &return_runtime); |
| 1427 |
| 1428 // Load map of {object}. |
| 1429 Node* object_map = LoadMap(object); |
| 1430 |
| 1431 // Lookup the {callable} and {object} map in the global instanceof cache. |
| 1432 // Note: This is safe because we clear the global instanceof cache whenever |
| 1433 // we change the prototype of any object. |
| 1434 Node* instanceof_cache_function = |
| 1435 LoadRoot(Heap::kInstanceofCacheFunctionRootIndex); |
| 1436 Node* instanceof_cache_map = LoadRoot(Heap::kInstanceofCacheMapRootIndex); |
| 1437 { |
| 1438 Label instanceof_cache_miss(this); |
| 1439 GotoUnless(WordEqual(instanceof_cache_function, callable), |
| 1440 &instanceof_cache_miss); |
| 1441 GotoUnless(WordEqual(instanceof_cache_map, object_map), |
| 1442 &instanceof_cache_miss); |
| 1443 var_result.Bind(LoadRoot(Heap::kInstanceofCacheAnswerRootIndex)); |
| 1444 Goto(&return_result); |
| 1445 Bind(&instanceof_cache_miss); |
| 1446 } |
| 1447 |
| 1448 // Goto runtime if {callable} is a Smi. |
| 1449 GotoIf(WordIsSmi(callable), &return_runtime); |
| 1450 |
| 1451 // Load map of {callable}. |
| 1452 Node* callable_map = LoadMap(callable); |
| 1453 |
| 1454 // Goto runtime if {callable} is not a JSFunction. |
| 1455 Node* callable_instance_type = LoadMapInstanceType(callable_map); |
| 1456 GotoUnless( |
| 1457 Word32Equal(callable_instance_type, Int32Constant(JS_FUNCTION_TYPE)), |
| 1458 &return_runtime); |
| 1459 |
| 1460 // Goto runtime if {callable} is not a constructor or has |
| 1461 // a non-instance "prototype". |
| 1462 Node* callable_bitfield = LoadMapBitField(callable_map); |
| 1463 GotoUnless( |
| 1464 Word32Equal(Word32And(callable_bitfield, |
| 1465 Int32Constant((1 << Map::kHasNonInstancePrototype) | |
| 1466 (1 << Map::kIsConstructor))), |
| 1467 Int32Constant(1 << Map::kIsConstructor)), |
| 1468 &return_runtime); |
| 1469 |
| 1470 // Get the "prototype" (or initial map) of the {callable}. |
| 1471 Node* callable_prototype = |
| 1472 LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset); |
| 1473 { |
| 1474 Variable var_callable_prototype(this, MachineRepresentation::kTagged); |
| 1475 Label callable_prototype_valid(this); |
| 1476 var_callable_prototype.Bind(callable_prototype); |
| 1477 |
| 1478 // Resolve the "prototype" if the {callable} has an initial map. Afterwards |
| 1479 // the {callable_prototype} will be either the JSReceiver prototype object |
| 1480 // or the hole value, which means that no instances of the {callable} were |
| 1481 // created so far and hence we should return false. |
| 1482 Node* callable_prototype_instance_type = |
| 1483 LoadInstanceType(callable_prototype); |
| 1484 GotoUnless( |
| 1485 Word32Equal(callable_prototype_instance_type, Int32Constant(MAP_TYPE)), |
| 1486 &callable_prototype_valid); |
| 1487 var_callable_prototype.Bind( |
| 1488 LoadObjectField(callable_prototype, Map::kPrototypeOffset)); |
| 1489 Goto(&callable_prototype_valid); |
| 1490 Bind(&callable_prototype_valid); |
| 1491 callable_prototype = var_callable_prototype.value(); |
| 1492 } |
| 1493 |
| 1494 // Update the global instanceof cache with the current {object} map and |
| 1495 // {callable}. The cached answer will be set when it is known below. |
| 1496 StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, callable); |
| 1497 StoreRoot(Heap::kInstanceofCacheMapRootIndex, object_map); |
| 1498 |
| 1499 // Loop through the prototype chain looking for the {callable} prototype. |
| 1500 Variable var_object_map(this, MachineRepresentation::kTagged); |
| 1501 var_object_map.Bind(object_map); |
| 1502 Label loop(this, &var_object_map); |
| 1503 Goto(&loop); |
| 1504 Bind(&loop); |
| 1505 { |
| 1506 Node* object_map = var_object_map.value(); |
| 1507 |
| 1508 // Check if the current {object} needs to be access checked. |
| 1509 Node* object_bitfield = LoadMapBitField(object_map); |
| 1510 GotoUnless( |
| 1511 Word32Equal(Word32And(object_bitfield, |
| 1512 Int32Constant(1 << Map::kIsAccessCheckNeeded)), |
| 1513 Int32Constant(0)), |
| 1514 &return_runtime); |
| 1515 |
| 1516 // Check if the current {object} is a proxy. |
| 1517 Node* object_instance_type = LoadMapInstanceType(object_map); |
| 1518 GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)), |
| 1519 &return_runtime); |
| 1520 |
| 1521 // Check the current {object} prototype. |
| 1522 Node* object_prototype = LoadMapPrototype(object_map); |
| 1523 GotoIf(WordEqual(object_prototype, callable_prototype), &return_true); |
| 1524 GotoIf(WordEqual(object_prototype, NullConstant()), &return_false); |
| 1525 |
| 1526 // Continue with the prototype. |
| 1527 var_object_map.Bind(LoadMap(object_prototype)); |
| 1528 Goto(&loop); |
| 1529 } |
| 1530 |
| 1531 Bind(&return_true); |
| 1532 StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(true)); |
| 1533 var_result.Bind(BooleanConstant(true)); |
| 1534 Goto(&return_result); |
| 1535 |
| 1536 Bind(&return_false); |
| 1537 StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(false)); |
| 1538 var_result.Bind(BooleanConstant(false)); |
| 1539 Goto(&return_result); |
| 1540 |
| 1541 Bind(&return_runtime); |
| 1542 { |
| 1543 // Invalidate the global instanceof cache. |
| 1544 StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, SmiConstant(0)); |
| 1545 // Fallback to the runtime implementation. |
| 1546 var_result.Bind( |
| 1547 CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object)); |
| 1548 } |
| 1549 Goto(&return_result); |
| 1550 |
| 1551 Bind(&return_result); |
| 1552 return var_result.value(); |
| 1553 } |
| 1554 |
1419 } // namespace internal | 1555 } // namespace internal |
1420 } // namespace v8 | 1556 } // namespace v8 |
OLD | NEW |