| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; | 1364 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; |
| 1365 | 1365 |
| 1366 // If the property is read-only, we leave the IC in its current | 1366 // If the property is read-only, we leave the IC in its current |
| 1367 // state. | 1367 // state. |
| 1368 if (lookup->IsReadOnly()) return false; | 1368 if (lookup->IsReadOnly()) return false; |
| 1369 | 1369 |
| 1370 return true; | 1370 return true; |
| 1371 } | 1371 } |
| 1372 | 1372 |
| 1373 | 1373 |
| 1374 static bool LookupForWrite(JSObject* receiver, | 1374 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1375 String* name, | 1375 Handle<String> name, |
| 1376 LookupResult* lookup) { | 1376 LookupResult* lookup) { |
| 1377 receiver->LocalLookup(name, lookup); | 1377 receiver->LocalLookup(*name, lookup); |
| 1378 if (!StoreICableLookup(lookup)) { | 1378 if (!StoreICableLookup(lookup)) { |
| 1379 return false; | 1379 return false; |
| 1380 } | 1380 } |
| 1381 | 1381 |
| 1382 if (lookup->type() == INTERCEPTOR && | 1382 if (lookup->type() == INTERCEPTOR && |
| 1383 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1383 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
| 1384 receiver->LocalLookupRealNamedProperty(name, lookup); | 1384 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1385 return StoreICableLookup(lookup); | 1385 return StoreICableLookup(lookup); |
| 1386 } | 1386 } |
| 1387 | 1387 |
| 1388 return true; | 1388 return true; |
| 1389 } | 1389 } |
| 1390 | 1390 |
| 1391 | 1391 |
| 1392 MaybeObject* StoreIC::Store(State state, | 1392 MaybeObject* StoreIC::Store(State state, |
| 1393 StrictModeFlag strict_mode, | 1393 StrictModeFlag strict_mode, |
| 1394 Handle<Object> object, | 1394 Handle<Object> object, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1415 // Ignore other stores where the receiver is not a JSObject. | 1415 // Ignore other stores where the receiver is not a JSObject. |
| 1416 // TODO(1475): Must check prototype chains of object wrappers. | 1416 // TODO(1475): Must check prototype chains of object wrappers. |
| 1417 return *value; | 1417 return *value; |
| 1418 } | 1418 } |
| 1419 | 1419 |
| 1420 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1420 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1421 | 1421 |
| 1422 // Check if the given name is an array index. | 1422 // Check if the given name is an array index. |
| 1423 uint32_t index; | 1423 uint32_t index; |
| 1424 if (name->AsArrayIndex(&index)) { | 1424 if (name->AsArrayIndex(&index)) { |
| 1425 HandleScope scope(isolate()); | |
| 1426 Handle<Object> result = SetElement(receiver, index, value, strict_mode); | 1425 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
| 1427 if (result.is_null()) return Failure::Exception(); | 1426 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1428 return *value; | 1427 return *value; |
| 1429 } | 1428 } |
| 1430 | 1429 |
| 1431 // Use specialized code for setting the length of arrays. | 1430 // Use specialized code for setting the length of arrays. |
| 1432 if (receiver->IsJSArray() | 1431 if (receiver->IsJSArray() |
| 1433 && name->Equals(isolate()->heap()->length_symbol()) | 1432 && name->Equals(isolate()->heap()->length_symbol()) |
| 1434 && JSArray::cast(*receiver)->AllowsSetElementsLength()) { | 1433 && Handle<JSArray>::cast(receiver)->AllowsSetElementsLength()) { |
| 1435 #ifdef DEBUG | 1434 #ifdef DEBUG |
| 1436 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1435 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1437 #endif | 1436 #endif |
| 1438 Builtins::Name target = (strict_mode == kStrictMode) | 1437 Handle<Code> stub = (strict_mode == kStrictMode) |
| 1439 ? Builtins::kStoreIC_ArrayLength_Strict | 1438 ? isolate()->builtins()->StoreIC_ArrayLength_Strict() |
| 1440 : Builtins::kStoreIC_ArrayLength; | 1439 : isolate()->builtins()->StoreIC_ArrayLength(); |
| 1441 set_target(isolate()->builtins()->builtin(target)); | 1440 set_target(*stub); |
| 1442 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1441 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1443 } | 1442 } |
| 1444 | 1443 |
| 1445 // Lookup the property locally in the receiver. | 1444 // Lookup the property locally in the receiver. |
| 1446 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1445 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1447 LookupResult lookup(isolate()); | 1446 LookupResult lookup(isolate()); |
| 1448 if (LookupForWrite(*receiver, *name, &lookup)) { | 1447 |
| 1448 if (LookupForWrite(receiver, name, &lookup)) { |
| 1449 // Generate a stub for this store. | 1449 // Generate a stub for this store. |
| 1450 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1450 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1451 } else { | 1451 } else { |
| 1452 // Strict mode doesn't allow setting non-existent global property | 1452 // Strict mode doesn't allow setting non-existent global property |
| 1453 // or an assignment to a read only property. | 1453 // or an assignment to a read only property. |
| 1454 if (strict_mode == kStrictMode) { | 1454 if (strict_mode == kStrictMode) { |
| 1455 if (lookup.IsFound() && lookup.IsReadOnly()) { | 1455 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1456 return TypeError("strict_read_only_property", object, name); | 1456 return TypeError("strict_read_only_property", object, name); |
| 1457 } else if (IsContextual(object)) { | 1457 } else if (IsContextual(object)) { |
| 1458 return ReferenceError("not_defined", name); | 1458 return ReferenceError("not_defined", name); |
| 1459 } | 1459 } |
| 1460 } | 1460 } |
| 1461 } | 1461 } |
| 1462 } | 1462 } |
| 1463 | 1463 |
| 1464 if (receiver->IsJSGlobalProxy()) { | 1464 if (receiver->IsJSGlobalProxy()) { |
| 1465 // TODO(ulan): find out why we patch this site even with --no-use-ic |
| 1465 // Generate a generic stub that goes to the runtime when we see a global | 1466 // Generate a generic stub that goes to the runtime when we see a global |
| 1466 // proxy as receiver. | 1467 // proxy as receiver. |
| 1467 Code* stub = (strict_mode == kStrictMode) | 1468 Handle<Code> stub = (strict_mode == kStrictMode) |
| 1468 ? global_proxy_stub_strict() | 1469 ? global_proxy_stub_strict() |
| 1469 : global_proxy_stub(); | 1470 : global_proxy_stub(); |
| 1470 if (target() != stub) { | 1471 if (target() != *stub) { |
| 1471 set_target(stub); | 1472 set_target(*stub); |
| 1472 #ifdef DEBUG | 1473 #ifdef DEBUG |
| 1473 TraceIC("StoreIC", name, state, target()); | 1474 TraceIC("StoreIC", name, state, target()); |
| 1474 #endif | 1475 #endif |
| 1475 } | 1476 } |
| 1476 } | 1477 } |
| 1477 | 1478 |
| 1478 // Set the property. | 1479 // Set the property. |
| 1479 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1480 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1480 } | 1481 } |
| 1481 | 1482 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1492 ASSERT(StoreICableLookup(lookup)); | 1493 ASSERT(StoreICableLookup(lookup)); |
| 1493 | 1494 |
| 1494 // If the property has a non-field type allowing map transitions | 1495 // If the property has a non-field type allowing map transitions |
| 1495 // where there is extra room in the object, we leave the IC in its | 1496 // where there is extra room in the object, we leave the IC in its |
| 1496 // current state. | 1497 // current state. |
| 1497 PropertyType type = lookup->type(); | 1498 PropertyType type = lookup->type(); |
| 1498 | 1499 |
| 1499 // Compute the code stub for this store; used for rewriting to | 1500 // Compute the code stub for this store; used for rewriting to |
| 1500 // monomorphic state and making sure that the code stub is in the | 1501 // monomorphic state and making sure that the code stub is in the |
| 1501 // stub cache. | 1502 // stub cache. |
| 1502 MaybeObject* maybe_code = NULL; | 1503 Handle<Code> code; |
| 1503 Object* code = NULL; | |
| 1504 switch (type) { | 1504 switch (type) { |
| 1505 case FIELD: { | 1505 case FIELD: |
| 1506 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1506 code = isolate()->stub_cache()->ComputeStoreField(name, |
| 1507 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); | 1507 receiver, |
| 1508 lookup->GetFieldIndex(), |
| 1509 Handle<Map>::null(), |
| 1510 strict_mode); |
| 1508 break; | 1511 break; |
| 1509 } | |
| 1510 case MAP_TRANSITION: { | 1512 case MAP_TRANSITION: { |
| 1511 if (lookup->GetAttributes() != NONE) return; | 1513 if (lookup->GetAttributes() != NONE) return; |
| 1512 HandleScope scope(isolate()); | |
| 1513 ASSERT(type == MAP_TRANSITION); | 1514 ASSERT(type == MAP_TRANSITION); |
| 1514 Handle<Map> transition(lookup->GetTransitionMap()); | 1515 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1515 int index = transition->PropertyIndexFor(*name); | 1516 int index = transition->PropertyIndexFor(*name); |
| 1516 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1517 code = isolate()->stub_cache()->ComputeStoreField( |
| 1517 *name, *receiver, index, *transition, strict_mode); | 1518 name, receiver, index, transition, strict_mode); |
| 1518 break; | 1519 break; |
| 1519 } | 1520 } |
| 1520 case NORMAL: { | 1521 case NORMAL: |
| 1521 if (receiver->IsGlobalObject()) { | 1522 if (receiver->IsGlobalObject()) { |
| 1522 // The stub generated for the global object picks the value directly | 1523 // The stub generated for the global object picks the value directly |
| 1523 // from the property cell. So the property must be directly on the | 1524 // from the property cell. So the property must be directly on the |
| 1524 // global object. | 1525 // global object. |
| 1525 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1526 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1526 JSGlobalPropertyCell* cell = | 1527 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
| 1527 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1528 code = isolate()->stub_cache()->ComputeStoreGlobal( |
| 1528 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal( | 1529 name, global, cell, strict_mode); |
| 1529 *name, *global, cell, strict_mode); | |
| 1530 } else { | 1530 } else { |
| 1531 if (lookup->holder() != *receiver) return; | 1531 if (lookup->holder() != *receiver) return; |
| 1532 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); | 1532 code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
| 1533 } | 1533 } |
| 1534 break; | 1534 break; |
| 1535 } | |
| 1536 case CALLBACKS: { | 1535 case CALLBACKS: { |
| 1537 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1536 Handle<Object> callback_object(lookup->GetCallbackObject()); |
| 1538 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1537 if (!callback_object->IsAccessorInfo()) return; |
| 1538 Handle<AccessorInfo> callback = |
| 1539 Handle<AccessorInfo>::cast(callback_object); |
| 1539 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1540 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1540 maybe_code = isolate()->stub_cache()->ComputeStoreCallback( | 1541 code = isolate()->stub_cache()->ComputeStoreCallback( |
| 1541 *name, *receiver, callback, strict_mode); | 1542 name, receiver, callback, strict_mode); |
| 1542 break; | 1543 break; |
| 1543 } | 1544 } |
| 1544 case INTERCEPTOR: { | 1545 case INTERCEPTOR: |
| 1545 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1546 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1546 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor( | 1547 code = isolate()->stub_cache()->ComputeStoreInterceptor( |
| 1547 *name, *receiver, strict_mode); | 1548 name, receiver, strict_mode); |
| 1548 break; | 1549 break; |
| 1549 } | |
| 1550 default: | 1550 default: |
| 1551 return; | 1551 return; |
| 1552 } | 1552 } |
| 1553 | 1553 |
| 1554 // If we're unable to compute the stub (not enough memory left), we | |
| 1555 // simply avoid updating the caches. | |
| 1556 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
| 1557 | |
| 1558 // Patch the call site depending on the state of the cache. | 1554 // Patch the call site depending on the state of the cache. |
| 1559 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1555 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1560 set_target(Code::cast(code)); | 1556 set_target(*code); |
| 1561 } else if (state == MONOMORPHIC) { | 1557 } else if (state == MONOMORPHIC) { |
| 1562 // Only move to megamorphic if the target changes. | 1558 // Only move to megamorphic if the target changes. |
| 1563 if (target() != Code::cast(code)) { | 1559 if (target() != *code) { |
| 1564 set_target((strict_mode == kStrictMode) | 1560 set_target((strict_mode == kStrictMode) |
| 1565 ? megamorphic_stub_strict() | 1561 ? megamorphic_stub_strict() |
| 1566 : megamorphic_stub()); | 1562 : megamorphic_stub()); |
| 1567 } | 1563 } |
| 1568 } else if (state == MEGAMORPHIC) { | 1564 } else if (state == MEGAMORPHIC) { |
| 1569 // Update the stub cache. | 1565 // Update the stub cache. |
| 1570 isolate()->stub_cache()->Set(*name, | 1566 isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
| 1571 receiver->map(), | |
| 1572 Code::cast(code)); | |
| 1573 } | 1567 } |
| 1574 | 1568 |
| 1575 #ifdef DEBUG | 1569 #ifdef DEBUG |
| 1576 TraceIC("StoreIC", name, state, target()); | 1570 TraceIC("StoreIC", name, state, target()); |
| 1577 #endif | 1571 #endif |
| 1578 } | 1572 } |
| 1579 | 1573 |
| 1580 | 1574 |
| 1581 static bool AddOneReceiverMapIfMissing(MapList* receiver_maps, | 1575 static bool AddOneReceiverMapIfMissing(MapList* receiver_maps, |
| 1582 Map* new_receiver_map) { | 1576 Map* new_receiver_map) { |
| (...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2083 NoHandleAllocation na; | 2077 NoHandleAllocation na; |
| 2084 ASSERT(args.length() == 2); | 2078 ASSERT(args.length() == 2); |
| 2085 KeyedLoadIC ic(isolate); | 2079 KeyedLoadIC ic(isolate); |
| 2086 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2080 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 2087 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); | 2081 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); |
| 2088 } | 2082 } |
| 2089 | 2083 |
| 2090 | 2084 |
| 2091 // Used from ic-<arch>.cc. | 2085 // Used from ic-<arch>.cc. |
| 2092 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 2086 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
| 2093 NoHandleAllocation na; | 2087 HandleScope scope; |
| 2094 ASSERT(args.length() == 3); | 2088 ASSERT(args.length() == 3); |
| 2095 StoreIC ic(isolate); | 2089 StoreIC ic(isolate); |
| 2096 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2090 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 2097 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2091 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 2098 return ic.Store(state, | 2092 return ic.Store(state, |
| 2099 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 2093 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 2100 args.at<Object>(0), | 2094 args.at<Object>(0), |
| 2101 args.at<String>(1), | 2095 args.at<String>(1), |
| 2102 args.at<Object>(2)); | 2096 args.at<Object>(2)); |
| 2103 } | 2097 } |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2621 #undef ADDR | 2615 #undef ADDR |
| 2622 }; | 2616 }; |
| 2623 | 2617 |
| 2624 | 2618 |
| 2625 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2619 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2626 return IC_utilities[id]; | 2620 return IC_utilities[id]; |
| 2627 } | 2621 } |
| 2628 | 2622 |
| 2629 | 2623 |
| 2630 } } // namespace v8::internal | 2624 } } // namespace v8::internal |
| OLD | NEW |