| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/api.h" | 8 #include "src/api.h" |
| 9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
| 10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 do { \ | 69 do { \ |
| 70 if (FLAG_trace_ic) { \ | 70 if (FLAG_trace_ic) { \ |
| 71 PrintF("[%s patching generic stub in ", type); \ | 71 PrintF("[%s patching generic stub in ", type); \ |
| 72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ | 72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ |
| 73 PrintF(" (%s)]\n", reason); \ | 73 PrintF(" (%s)]\n", reason); \ |
| 74 } \ | 74 } \ |
| 75 } while (false) | 75 } while (false) |
| 76 | 76 |
| 77 #else | 77 #else |
| 78 | 78 |
| 79 #define TRACE_GENERIC_IC(isolate, type, reason) | 79 #define TRACE_GENERIC_IC(isolate, type, reason) \ |
| 80 do { \ |
| 81 if (FLAG_trace_ic) { \ |
| 82 PrintF("[%s patching generic stub in ", type); \ |
| 83 PrintF("(see below) (%s)]\n", reason); \ |
| 84 } \ |
| 85 } while (false) |
| 80 | 86 |
| 81 #endif // DEBUG | 87 #endif // DEBUG |
| 82 | 88 |
| 83 | 89 |
| 84 void IC::TraceIC(const char* type, Handle<Object> name) { | 90 void IC::TraceIC(const char* type, Handle<Object> name) { |
| 85 if (FLAG_trace_ic) { | 91 if (FLAG_trace_ic) { |
| 86 Code* new_target = raw_target(); | 92 Code* new_target = raw_target(); |
| 87 State new_state = new_target->ic_state(); | 93 State new_state = new_target->ic_state(); |
| 88 TraceIC(type, name, state(), new_state); | 94 TraceIC(type, name, state(), new_state); |
| 89 } | 95 } |
| (...skipping 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1133 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); | 1139 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); |
| 1134 } | 1140 } |
| 1135 | 1141 |
| 1136 DCHECK(state() != GENERIC); | 1142 DCHECK(state() != GENERIC); |
| 1137 | 1143 |
| 1138 // Determine the list of receiver maps that this call site has seen, | 1144 // Determine the list of receiver maps that this call site has seen, |
| 1139 // adding the map that was just encountered. | 1145 // adding the map that was just encountered. |
| 1140 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { | 1146 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { |
| 1141 // If the miss wasn't due to an unseen map, a polymorphic stub | 1147 // If the miss wasn't due to an unseen map, a polymorphic stub |
| 1142 // won't help, use the generic stub. | 1148 // won't help, use the generic stub. |
| 1143 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); | 1149 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice"); |
| 1144 return generic_stub(); | 1150 return generic_stub(); |
| 1145 } | 1151 } |
| 1146 | 1152 |
| 1147 // If the maximum number of receiver maps has been exceeded, use the generic | 1153 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1148 // version of the IC. | 1154 // version of the IC. |
| 1149 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1155 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1150 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); | 1156 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded"); |
| 1151 return generic_stub(); | 1157 return generic_stub(); |
| 1152 } | 1158 } |
| 1153 | 1159 |
| 1154 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps); | 1160 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps); |
| 1155 } | 1161 } |
| 1156 | 1162 |
| 1157 | 1163 |
| 1158 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, | 1164 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, |
| 1159 Handle<Object> key) { | 1165 Handle<Object> key) { |
| 1160 if (MigrateDeprecated(object)) { | 1166 if (MigrateDeprecated(object)) { |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, | 1370 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, |
| 1365 JSReceiver::StoreFromKeyed store_mode) { | 1371 JSReceiver::StoreFromKeyed store_mode) { |
| 1366 if (state() == UNINITIALIZED) { | 1372 if (state() == UNINITIALIZED) { |
| 1367 // This is the first time we execute this inline cache. Set the target to | 1373 // This is the first time we execute this inline cache. Set the target to |
| 1368 // the pre monomorphic stub to delay setting the monomorphic state. | 1374 // the pre monomorphic stub to delay setting the monomorphic state. |
| 1369 set_target(*pre_monomorphic_stub()); | 1375 set_target(*pre_monomorphic_stub()); |
| 1370 TRACE_IC("StoreIC", lookup->name()); | 1376 TRACE_IC("StoreIC", lookup->name()); |
| 1371 return; | 1377 return; |
| 1372 } | 1378 } |
| 1373 | 1379 |
| 1374 Handle<Code> code = LookupForWrite(lookup, value, store_mode) | 1380 bool use_ic = LookupForWrite(lookup, value, store_mode); |
| 1375 ? ComputeHandler(lookup, value) | 1381 if (!use_ic) { |
| 1376 : slow_stub(); | 1382 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'"); |
| 1383 } |
| 1384 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub(); |
| 1377 | 1385 |
| 1378 PatchCache(lookup->name(), code); | 1386 PatchCache(lookup->name(), code); |
| 1379 TRACE_IC("StoreIC", lookup->name()); | 1387 TRACE_IC("StoreIC", lookup->name()); |
| 1380 } | 1388 } |
| 1381 | 1389 |
| 1382 | 1390 |
| 1383 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, | 1391 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, |
| 1384 Handle<Object> value, | 1392 Handle<Object> value, |
| 1385 CacheHolderFlag cache_holder) { | 1393 CacheHolderFlag cache_holder) { |
| 1386 DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); | 1394 DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); |
| 1387 | 1395 |
| 1388 // This is currently guaranteed by checks in StoreIC::Store. | 1396 // This is currently guaranteed by checks in StoreIC::Store. |
| 1389 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); | 1397 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); |
| 1390 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); | 1398 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
| 1391 DCHECK(!receiver->IsAccessCheckNeeded()); | 1399 DCHECK(!receiver->IsAccessCheckNeeded()); |
| 1392 | 1400 |
| 1393 switch (lookup->state()) { | 1401 switch (lookup->state()) { |
| 1394 case LookupIterator::TRANSITION: { | 1402 case LookupIterator::TRANSITION: { |
| 1395 Handle<Map> transition = lookup->transition_map(); | 1403 Handle<Map> transition = lookup->transition_map(); |
| 1396 // Currently not handled by CompileStoreTransition. | 1404 // Currently not handled by CompileStoreTransition. |
| 1397 if (!holder->HasFastProperties()) break; | 1405 if (!holder->HasFastProperties()) { |
| 1406 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow"); |
| 1407 break; |
| 1408 } |
| 1398 | 1409 |
| 1399 DCHECK(lookup->IsCacheableTransition()); | 1410 DCHECK(lookup->IsCacheableTransition()); |
| 1400 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1411 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1401 return compiler.CompileStoreTransition(transition, lookup->name()); | 1412 return compiler.CompileStoreTransition(transition, lookup->name()); |
| 1402 } | 1413 } |
| 1403 | 1414 |
| 1404 case LookupIterator::INTERCEPTOR: { | 1415 case LookupIterator::INTERCEPTOR: { |
| 1405 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); | 1416 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1406 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1417 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1407 return compiler.CompileStoreInterceptor(lookup->name()); | 1418 return compiler.CompileStoreInterceptor(lookup->name()); |
| 1408 } | 1419 } |
| 1409 | 1420 |
| 1410 case LookupIterator::ACCESSOR: { | 1421 case LookupIterator::ACCESSOR: { |
| 1411 if (!holder->HasFastProperties()) break; | 1422 if (!holder->HasFastProperties()) { |
| 1423 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map"); |
| 1424 break; |
| 1425 } |
| 1412 Handle<Object> accessors = lookup->GetAccessors(); | 1426 Handle<Object> accessors = lookup->GetAccessors(); |
| 1413 if (accessors->IsExecutableAccessorInfo()) { | 1427 if (accessors->IsExecutableAccessorInfo()) { |
| 1414 Handle<ExecutableAccessorInfo> info = | 1428 Handle<ExecutableAccessorInfo> info = |
| 1415 Handle<ExecutableAccessorInfo>::cast(accessors); | 1429 Handle<ExecutableAccessorInfo>::cast(accessors); |
| 1416 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1430 if (v8::ToCData<Address>(info->setter()) == 0) { |
| 1431 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0"); |
| 1432 break; |
| 1433 } |
| 1417 if (!ExecutableAccessorInfo::IsCompatibleReceiverType( | 1434 if (!ExecutableAccessorInfo::IsCompatibleReceiverType( |
| 1418 isolate(), info, receiver_type())) { | 1435 isolate(), info, receiver_type())) { |
| 1436 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type"); |
| 1419 break; | 1437 break; |
| 1420 } | 1438 } |
| 1421 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1439 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1422 return compiler.CompileStoreCallback(receiver, lookup->name(), info); | 1440 return compiler.CompileStoreCallback(receiver, lookup->name(), info); |
| 1423 } else if (accessors->IsAccessorPair()) { | 1441 } else if (accessors->IsAccessorPair()) { |
| 1424 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), | 1442 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), |
| 1425 isolate()); | 1443 isolate()); |
| 1426 if (!setter->IsJSFunction()) break; | 1444 if (!setter->IsJSFunction()) { |
| 1445 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function"); |
| 1446 break; |
| 1447 } |
| 1427 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 1448 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
| 1428 CallOptimization call_optimization(function); | 1449 CallOptimization call_optimization(function); |
| 1429 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1450 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1430 if (call_optimization.is_simple_api_call() && | 1451 if (call_optimization.is_simple_api_call() && |
| 1431 call_optimization.IsCompatibleReceiver(receiver, holder)) { | 1452 call_optimization.IsCompatibleReceiver(receiver, holder)) { |
| 1432 return compiler.CompileStoreCallback(receiver, lookup->name(), | 1453 return compiler.CompileStoreCallback(receiver, lookup->name(), |
| 1433 call_optimization); | 1454 call_optimization); |
| 1434 } | 1455 } |
| 1435 return compiler.CompileStoreViaSetter(receiver, lookup->name(), | 1456 return compiler.CompileStoreViaSetter(receiver, lookup->name(), |
| 1436 Handle<JSFunction>::cast(setter)); | 1457 Handle<JSFunction>::cast(setter)); |
| 1437 } | 1458 } |
| 1438 // TODO(dcarney): Handle correctly. | 1459 // TODO(dcarney): Handle correctly. |
| 1439 DCHECK(accessors->IsDeclaredAccessorInfo()); | 1460 DCHECK(accessors->IsDeclaredAccessorInfo()); |
| 1461 TRACE_GENERIC_IC(isolate(), "StoreIC", "declared accessor info"); |
| 1440 break; | 1462 break; |
| 1441 } | 1463 } |
| 1442 | 1464 |
| 1443 case LookupIterator::DATA: { | 1465 case LookupIterator::DATA: { |
| 1444 if (lookup->is_dictionary_holder()) { | 1466 if (lookup->is_dictionary_holder()) { |
| 1445 if (holder->IsGlobalObject()) { | 1467 if (holder->IsGlobalObject()) { |
| 1446 Handle<PropertyCell> cell = lookup->GetPropertyCell(); | 1468 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
| 1447 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | 1469 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
| 1448 StoreGlobalStub stub(isolate(), union_type->IsConstant(), | 1470 StoreGlobalStub stub(isolate(), union_type->IsConstant(), |
| 1449 receiver->IsJSGlobalProxy()); | 1471 receiver->IsJSGlobalProxy()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1470 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), | 1492 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), |
| 1471 lookup->representation()); | 1493 lookup->representation()); |
| 1472 return stub.GetCode(); | 1494 return stub.GetCode(); |
| 1473 } | 1495 } |
| 1474 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1496 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1475 return compiler.CompileStoreField(lookup); | 1497 return compiler.CompileStoreField(lookup); |
| 1476 } | 1498 } |
| 1477 | 1499 |
| 1478 // -------------- Constant properties -------------- | 1500 // -------------- Constant properties -------------- |
| 1479 DCHECK(lookup->property_details().type() == CONSTANT); | 1501 DCHECK(lookup->property_details().type() == CONSTANT); |
| 1502 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property"); |
| 1480 break; | 1503 break; |
| 1481 } | 1504 } |
| 1482 | 1505 |
| 1483 case LookupIterator::ACCESS_CHECK: | 1506 case LookupIterator::ACCESS_CHECK: |
| 1484 case LookupIterator::JSPROXY: | 1507 case LookupIterator::JSPROXY: |
| 1485 case LookupIterator::NOT_FOUND: | 1508 case LookupIterator::NOT_FOUND: |
| 1486 UNREACHABLE(); | 1509 UNREACHABLE(); |
| 1487 } | 1510 } |
| 1488 return slow_stub(); | 1511 return slow_stub(); |
| 1489 } | 1512 } |
| 1490 | 1513 |
| 1491 | 1514 |
| 1492 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1515 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
| 1493 KeyedAccessStoreMode store_mode) { | 1516 KeyedAccessStoreMode store_mode) { |
| 1494 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1517 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1495 // via megamorphic stubs, since they don't have a map in their relocation info | 1518 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1496 // and so the stubs can't be harvested for the object needed for a map check. | 1519 // and so the stubs can't be harvested for the object needed for a map check. |
| 1497 if (target()->type() != Code::NORMAL) { | 1520 if (target()->type() != Code::NORMAL) { |
| 1498 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1521 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type"); |
| 1499 return generic_stub(); | 1522 return generic_stub(); |
| 1500 } | 1523 } |
| 1501 | 1524 |
| 1502 Handle<Map> receiver_map(receiver->map(), isolate()); | 1525 Handle<Map> receiver_map(receiver->map(), isolate()); |
| 1503 MapHandleList target_receiver_maps; | 1526 MapHandleList target_receiver_maps; |
| 1504 TargetMaps(&target_receiver_maps); | 1527 TargetMaps(&target_receiver_maps); |
| 1505 if (target_receiver_maps.length() == 0) { | 1528 if (target_receiver_maps.length() == 0) { |
| 1506 Handle<Map> monomorphic_map = | 1529 Handle<Map> monomorphic_map = |
| 1507 ComputeTransitionedMap(receiver_map, store_mode); | 1530 ComputeTransitionedMap(receiver_map, store_mode); |
| 1508 store_mode = GetNonTransitioningStoreMode(store_mode); | 1531 store_mode = GetNonTransitioningStoreMode(store_mode); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1554 if (IsTransitionStoreMode(store_mode)) { | 1577 if (IsTransitionStoreMode(store_mode)) { |
| 1555 Handle<Map> transitioned_receiver_map = | 1578 Handle<Map> transitioned_receiver_map = |
| 1556 ComputeTransitionedMap(receiver_map, store_mode); | 1579 ComputeTransitionedMap(receiver_map, store_mode); |
| 1557 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, | 1580 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, |
| 1558 transitioned_receiver_map); | 1581 transitioned_receiver_map); |
| 1559 } | 1582 } |
| 1560 | 1583 |
| 1561 if (!map_added) { | 1584 if (!map_added) { |
| 1562 // If the miss wasn't due to an unseen map, a polymorphic stub | 1585 // If the miss wasn't due to an unseen map, a polymorphic stub |
| 1563 // won't help, use the generic stub. | 1586 // won't help, use the generic stub. |
| 1564 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); | 1587 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice"); |
| 1565 return generic_stub(); | 1588 return generic_stub(); |
| 1566 } | 1589 } |
| 1567 | 1590 |
| 1568 // If the maximum number of receiver maps has been exceeded, use the generic | 1591 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1569 // version of the IC. | 1592 // version of the IC. |
| 1570 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1593 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1571 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); | 1594 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "max polymorph exceeded"); |
| 1572 return generic_stub(); | 1595 return generic_stub(); |
| 1573 } | 1596 } |
| 1574 | 1597 |
| 1575 // Make sure all polymorphic handlers have the same store mode, otherwise the | 1598 // Make sure all polymorphic handlers have the same store mode, otherwise the |
| 1576 // generic stub must be used. | 1599 // generic stub must be used. |
| 1577 store_mode = GetNonTransitioningStoreMode(store_mode); | 1600 store_mode = GetNonTransitioningStoreMode(store_mode); |
| 1578 if (old_store_mode != STANDARD_STORE) { | 1601 if (old_store_mode != STANDARD_STORE) { |
| 1579 if (store_mode == STANDARD_STORE) { | 1602 if (store_mode == STANDARD_STORE) { |
| 1580 store_mode = old_store_mode; | 1603 store_mode = old_store_mode; |
| 1581 } else if (store_mode != old_store_mode) { | 1604 } else if (store_mode != old_store_mode) { |
| 1582 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch"); | 1605 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch"); |
| 1583 return generic_stub(); | 1606 return generic_stub(); |
| 1584 } | 1607 } |
| 1585 } | 1608 } |
| 1586 | 1609 |
| 1587 // If the store mode isn't the standard mode, make sure that all polymorphic | 1610 // If the store mode isn't the standard mode, make sure that all polymorphic |
| 1588 // receivers are either external arrays, or all "normal" arrays. Otherwise, | 1611 // receivers are either external arrays, or all "normal" arrays. Otherwise, |
| 1589 // use the generic stub. | 1612 // use the generic stub. |
| 1590 if (store_mode != STANDARD_STORE) { | 1613 if (store_mode != STANDARD_STORE) { |
| 1591 int external_arrays = 0; | 1614 int external_arrays = 0; |
| 1592 for (int i = 0; i < target_receiver_maps.length(); ++i) { | 1615 for (int i = 0; i < target_receiver_maps.length(); ++i) { |
| 1593 if (target_receiver_maps[i]->has_external_array_elements() || | 1616 if (target_receiver_maps[i]->has_external_array_elements() || |
| 1594 target_receiver_maps[i]->has_fixed_typed_array_elements()) { | 1617 target_receiver_maps[i]->has_fixed_typed_array_elements()) { |
| 1595 external_arrays++; | 1618 external_arrays++; |
| 1596 } | 1619 } |
| 1597 } | 1620 } |
| 1598 if (external_arrays != 0 && | 1621 if (external_arrays != 0 && |
| 1599 external_arrays != target_receiver_maps.length()) { | 1622 external_arrays != target_receiver_maps.length()) { |
| 1600 TRACE_GENERIC_IC(isolate(), "KeyedIC", | 1623 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", |
| 1601 "unsupported combination of external and normal arrays"); | 1624 "unsupported combination of external and normal arrays"); |
| 1602 return generic_stub(); | 1625 return generic_stub(); |
| 1603 } | 1626 } |
| 1604 } | 1627 } |
| 1605 | 1628 |
| 1606 return PropertyICCompiler::ComputeKeyedStorePolymorphic( | 1629 return PropertyICCompiler::ComputeKeyedStorePolymorphic( |
| 1607 &target_receiver_maps, store_mode, strict_mode()); | 1630 &target_receiver_maps, store_mode, strict_mode()); |
| 1608 } | 1631 } |
| 1609 | 1632 |
| 1610 | 1633 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1745 | 1768 |
| 1746 Handle<Object> store_handle; | 1769 Handle<Object> store_handle; |
| 1747 Handle<Code> stub = generic_stub(); | 1770 Handle<Code> stub = generic_stub(); |
| 1748 | 1771 |
| 1749 if (key->IsInternalizedString()) { | 1772 if (key->IsInternalizedString()) { |
| 1750 ASSIGN_RETURN_ON_EXCEPTION( | 1773 ASSIGN_RETURN_ON_EXCEPTION( |
| 1751 isolate(), store_handle, | 1774 isolate(), store_handle, |
| 1752 StoreIC::Store(object, Handle<String>::cast(key), value, | 1775 StoreIC::Store(object, Handle<String>::cast(key), value, |
| 1753 JSReceiver::MAY_BE_STORE_FROM_KEYED), | 1776 JSReceiver::MAY_BE_STORE_FROM_KEYED), |
| 1754 Object); | 1777 Object); |
| 1755 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1778 if (!is_target_set()) { |
| 1756 set_target(*stub); | 1779 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", |
| 1780 "unhandled internalized string key"); |
| 1781 TRACE_IC("StoreIC", key); |
| 1782 set_target(*stub); |
| 1783 } |
| 1757 return store_handle; | 1784 return store_handle; |
| 1758 } | 1785 } |
| 1759 | 1786 |
| 1760 bool use_ic = | 1787 bool use_ic = |
| 1761 FLAG_use_ic && !object->IsStringWrapper() && | 1788 FLAG_use_ic && !object->IsStringWrapper() && |
| 1762 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() && | 1789 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() && |
| 1763 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed()); | 1790 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed()); |
| 1764 if (use_ic && !object->IsSmi()) { | 1791 if (use_ic && !object->IsSmi()) { |
| 1765 // Don't use ICs for maps of the objects in Array's prototype chain. We | 1792 // Don't use ICs for maps of the objects in Array's prototype chain. We |
| 1766 // expect to be able to trap element sets to objects with those maps in | 1793 // expect to be able to trap element sets to objects with those maps in |
| 1767 // the runtime to enable optimization of element hole access. | 1794 // the runtime to enable optimization of element hole access. |
| 1768 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); | 1795 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); |
| 1769 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; | 1796 if (heap_object->map()->IsMapInArrayPrototypeChain()) { |
| 1797 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype"); |
| 1798 use_ic = false; |
| 1799 } |
| 1770 } | 1800 } |
| 1771 | 1801 |
| 1772 if (use_ic) { | 1802 if (use_ic) { |
| 1773 DCHECK(!object->IsAccessCheckNeeded()); | 1803 DCHECK(!object->IsAccessCheckNeeded()); |
| 1774 | 1804 |
| 1775 if (object->IsJSObject()) { | 1805 if (object->IsJSObject()) { |
| 1776 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1806 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1777 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null(); | 1807 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null(); |
| 1778 if (receiver->elements()->map() == | 1808 if (receiver->elements()->map() == |
| 1779 isolate()->heap()->sloppy_arguments_elements_map()) { | 1809 isolate()->heap()->sloppy_arguments_elements_map()) { |
| 1780 if (strict_mode() == SLOPPY) { | 1810 if (strict_mode() == SLOPPY) { |
| 1781 stub = sloppy_arguments_stub(); | 1811 stub = sloppy_arguments_stub(); |
| 1812 } else { |
| 1813 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver"); |
| 1782 } | 1814 } |
| 1783 } else if (key_is_smi_like && | 1815 } else if (key_is_smi_like && |
| 1784 !(target().is_identical_to(sloppy_arguments_stub()))) { | 1816 !(target().is_identical_to(sloppy_arguments_stub()))) { |
| 1785 // We should go generic if receiver isn't a dictionary, but our | 1817 // We should go generic if receiver isn't a dictionary, but our |
| 1786 // prototype chain does have dictionary elements. This ensures that | 1818 // prototype chain does have dictionary elements. This ensures that |
| 1787 // other non-dictionary receivers in the polymorphic case benefit | 1819 // other non-dictionary receivers in the polymorphic case benefit |
| 1788 // from fast path keyed stores. | 1820 // from fast path keyed stores. |
| 1789 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) { | 1821 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) { |
| 1790 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); | 1822 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); |
| 1791 stub = StoreElementStub(receiver, store_mode); | 1823 stub = StoreElementStub(receiver, store_mode); |
| 1824 } else { |
| 1825 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype"); |
| 1792 } | 1826 } |
| 1827 } else { |
| 1828 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key"); |
| 1793 } | 1829 } |
| 1830 } else { |
| 1831 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver"); |
| 1794 } | 1832 } |
| 1795 } | 1833 } |
| 1796 | 1834 |
| 1797 if (store_handle.is_null()) { | 1835 if (store_handle.is_null()) { |
| 1798 ASSIGN_RETURN_ON_EXCEPTION( | 1836 ASSIGN_RETURN_ON_EXCEPTION( |
| 1799 isolate(), store_handle, | 1837 isolate(), store_handle, |
| 1800 Runtime::SetObjectProperty(isolate(), object, key, value, | 1838 Runtime::SetObjectProperty(isolate(), object, key, value, |
| 1801 strict_mode()), | 1839 strict_mode()), |
| 1802 Object); | 1840 Object); |
| 1803 } | 1841 } |
| 1804 | 1842 |
| 1805 DCHECK(!is_target_set()); | 1843 DCHECK(!is_target_set()); |
| 1806 Code* generic = *generic_stub(); | 1844 Code* generic = *generic_stub(); |
| 1807 if (*stub == generic) { | 1845 if (*stub == generic) { |
| 1808 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1846 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
| 1809 } | 1847 } |
| 1848 if (*stub == *slow_stub()) { |
| 1849 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub"); |
| 1850 } |
| 1810 DCHECK(!stub.is_null()); | 1851 DCHECK(!stub.is_null()); |
| 1811 set_target(*stub); | 1852 set_target(*stub); |
| 1812 TRACE_IC("StoreIC", key); | 1853 TRACE_IC("StoreIC", key); |
| 1813 | 1854 |
| 1814 return store_handle; | 1855 return store_handle; |
| 1815 } | 1856 } |
| 1816 | 1857 |
| 1817 | 1858 |
| 1818 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, | 1859 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, |
| 1819 Handle<TypeFeedbackVector> vector, | 1860 Handle<TypeFeedbackVector> vector, |
| (...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2607 static const Address IC_utilities[] = { | 2648 static const Address IC_utilities[] = { |
| 2608 #define ADDR(name) FUNCTION_ADDR(name), | 2649 #define ADDR(name) FUNCTION_ADDR(name), |
| 2609 IC_UTIL_LIST(ADDR) NULL | 2650 IC_UTIL_LIST(ADDR) NULL |
| 2610 #undef ADDR | 2651 #undef ADDR |
| 2611 }; | 2652 }; |
| 2612 | 2653 |
| 2613 | 2654 |
| 2614 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } | 2655 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } |
| 2615 } | 2656 } |
| 2616 } // namespace v8::internal | 2657 } // namespace v8::internal |
| OLD | NEW |