| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 // present) to guarantee failure by holding an invalid map (the null | 336 // present) to guarantee failure by holding an invalid map (the null |
| 337 // value). The offset can be patched to anything. | 337 // value). The offset can be patched to anything. |
| 338 PatchInlinedStore(address, Heap::null_value(), 0); | 338 PatchInlinedStore(address, Heap::null_value(), 0); |
| 339 } | 339 } |
| 340 | 340 |
| 341 | 341 |
| 342 void StoreIC::Clear(Address address, Code* target) { | 342 void StoreIC::Clear(Address address, Code* target) { |
| 343 if (target->ic_state() == UNINITIALIZED) return; | 343 if (target->ic_state() == UNINITIALIZED) return; |
| 344 ClearInlinedVersion(address); | 344 ClearInlinedVersion(address); |
| 345 SetTargetAtAddress(address, | 345 SetTargetAtAddress(address, |
| 346 target->extra_ic_state() == kStoreICStrict | 346 (target->extra_ic_state() == kStrictMode) |
| 347 ? initialize_stub_strict() | 347 ? initialize_stub_strict() |
| 348 : initialize_stub()); | 348 : initialize_stub()); |
| 349 } | 349 } |
| 350 | 350 |
| 351 | 351 |
| 352 void KeyedStoreIC::ClearInlinedVersion(Address address) { | 352 void KeyedStoreIC::ClearInlinedVersion(Address address) { |
| 353 // Insert null as the elements map to check for. This will make | 353 // Insert null as the elements map to check for. This will make |
| 354 // sure that the elements fast-case map check fails so that control | 354 // sure that the elements fast-case map check fails so that control |
| 355 // flows to the IC instead of the inlined version. | 355 // flows to the IC instead of the inlined version. |
| 356 PatchInlinedStore(address, Heap::null_value()); | 356 PatchInlinedStore(address, Heap::null_value()); |
| 357 } | 357 } |
| 358 | 358 |
| 359 | 359 |
| 360 void KeyedStoreIC::RestoreInlinedVersion(Address address) { | 360 void KeyedStoreIC::RestoreInlinedVersion(Address address) { |
| 361 // Restore the fast-case elements map check so that the inlined | 361 // Restore the fast-case elements map check so that the inlined |
| 362 // version can be used again. | 362 // version can be used again. |
| 363 PatchInlinedStore(address, Heap::fixed_array_map()); | 363 PatchInlinedStore(address, Heap::fixed_array_map()); |
| 364 } | 364 } |
| 365 | 365 |
| 366 | 366 |
| 367 void KeyedStoreIC::Clear(Address address, Code* target) { | 367 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 368 if (target->ic_state() == UNINITIALIZED) return; | 368 if (target->ic_state() == UNINITIALIZED) return; |
| 369 SetTargetAtAddress(address, initialize_stub()); | 369 SetTargetAtAddress(address, |
| 370 (target->extra_ic_state() == kStrictMode) |
| 371 ? initialize_stub_strict() |
| 372 : initialize_stub()); |
| 370 } | 373 } |
| 371 | 374 |
| 372 | 375 |
| 373 static bool HasInterceptorGetter(JSObject* object) { | 376 static bool HasInterceptorGetter(JSObject* object) { |
| 374 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 377 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 375 } | 378 } |
| 376 | 379 |
| 377 | 380 |
| 378 static void LookupForRead(Object* object, | 381 static void LookupForRead(Object* object, |
| 379 String* name, | 382 String* name, |
| (...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1220 if (use_ic) { | 1223 if (use_ic) { |
| 1221 Code* stub = generic_stub(); | 1224 Code* stub = generic_stub(); |
| 1222 if (state == UNINITIALIZED) { | 1225 if (state == UNINITIALIZED) { |
| 1223 if (object->IsString() && key->IsNumber()) { | 1226 if (object->IsString() && key->IsNumber()) { |
| 1224 stub = string_stub(); | 1227 stub = string_stub(); |
| 1225 } else if (object->IsJSObject()) { | 1228 } else if (object->IsJSObject()) { |
| 1226 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1229 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1227 if (receiver->HasExternalArrayElements()) { | 1230 if (receiver->HasExternalArrayElements()) { |
| 1228 MaybeObject* probe = | 1231 MaybeObject* probe = |
| 1229 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, | 1232 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, |
| 1230 false); | 1233 false, |
| 1234 kNonStrictMode); |
| 1231 stub = probe->IsFailure() ? | 1235 stub = probe->IsFailure() ? |
| 1232 NULL : Code::cast(probe->ToObjectUnchecked()); | 1236 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1233 } else if (receiver->HasIndexedInterceptor()) { | 1237 } else if (receiver->HasIndexedInterceptor()) { |
| 1234 stub = indexed_interceptor_stub(); | 1238 stub = indexed_interceptor_stub(); |
| 1235 } else if (receiver->HasPixelElements()) { | 1239 } else if (receiver->HasPixelElements()) { |
| 1236 MaybeObject* probe = | 1240 MaybeObject* probe = |
| 1237 StubCache::ComputeKeyedLoadPixelArray(*receiver); | 1241 StubCache::ComputeKeyedLoadPixelArray(*receiver); |
| 1238 stub = probe->IsFailure() ? | 1242 stub = probe->IsFailure() ? |
| 1239 NULL : Code::cast(probe->ToObjectUnchecked()); | 1243 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1240 } else if (key->IsSmi() && | 1244 } else if (key->IsSmi() && |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1376 object->LocalLookupRealNamedProperty(name, lookup); | 1380 object->LocalLookupRealNamedProperty(name, lookup); |
| 1377 return StoreICableLookup(lookup); | 1381 return StoreICableLookup(lookup); |
| 1378 } | 1382 } |
| 1379 } | 1383 } |
| 1380 | 1384 |
| 1381 return true; | 1385 return true; |
| 1382 } | 1386 } |
| 1383 | 1387 |
| 1384 | 1388 |
| 1385 MaybeObject* StoreIC::Store(State state, | 1389 MaybeObject* StoreIC::Store(State state, |
| 1386 Code::ExtraICState extra_ic_state, | 1390 StrictModeFlag strict_mode, |
| 1387 Handle<Object> object, | 1391 Handle<Object> object, |
| 1388 Handle<String> name, | 1392 Handle<String> name, |
| 1389 Handle<Object> value) { | 1393 Handle<Object> value) { |
| 1390 // If the object is undefined or null it's illegal to try to set any | 1394 // If the object is undefined or null it's illegal to try to set any |
| 1391 // properties on it; throw a TypeError in that case. | 1395 // properties on it; throw a TypeError in that case. |
| 1392 if (object->IsUndefined() || object->IsNull()) { | 1396 if (object->IsUndefined() || object->IsNull()) { |
| 1393 return TypeError("non_object_property_store", object, name); | 1397 return TypeError("non_object_property_store", object, name); |
| 1394 } | 1398 } |
| 1395 | 1399 |
| 1396 // Ignore stores where the receiver is not a JSObject. | 1400 // Ignore stores where the receiver is not a JSObject. |
| 1397 if (!object->IsJSObject()) return *value; | 1401 if (!object->IsJSObject()) return *value; |
| 1398 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1402 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1399 | 1403 |
| 1400 // Check if the given name is an array index. | 1404 // Check if the given name is an array index. |
| 1401 uint32_t index; | 1405 uint32_t index; |
| 1402 if (name->AsArrayIndex(&index)) { | 1406 if (name->AsArrayIndex(&index)) { |
| 1403 HandleScope scope; | 1407 HandleScope scope; |
| 1404 Handle<Object> result = SetElement(receiver, index, value); | 1408 Handle<Object> result = SetElement(receiver, index, value); |
| 1405 if (result.is_null()) return Failure::Exception(); | 1409 if (result.is_null()) return Failure::Exception(); |
| 1406 return *value; | 1410 return *value; |
| 1407 } | 1411 } |
| 1408 | 1412 |
| 1409 // Use specialized code for setting the length of arrays. | 1413 // Use specialized code for setting the length of arrays. |
| 1410 if (receiver->IsJSArray() | 1414 if (receiver->IsJSArray() |
| 1411 && name->Equals(Heap::length_symbol()) | 1415 && name->Equals(Heap::length_symbol()) |
| 1412 && receiver->AllowsSetElementsLength()) { | 1416 && receiver->AllowsSetElementsLength()) { |
| 1413 #ifdef DEBUG | 1417 #ifdef DEBUG |
| 1414 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1418 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1415 #endif | 1419 #endif |
| 1416 Builtins::Name target = (extra_ic_state == kStoreICStrict) | 1420 Builtins::Name target = (strict_mode == kStrictMode) |
| 1417 ? Builtins::StoreIC_ArrayLength_Strict | 1421 ? Builtins::StoreIC_ArrayLength_Strict |
| 1418 : Builtins::StoreIC_ArrayLength; | 1422 : Builtins::StoreIC_ArrayLength; |
| 1419 set_target(Builtins::builtin(target)); | 1423 set_target(Builtins::builtin(target)); |
| 1420 return receiver->SetProperty(*name, *value, NONE); | 1424 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1421 } | 1425 } |
| 1422 | 1426 |
| 1423 // Lookup the property locally in the receiver. | 1427 // Lookup the property locally in the receiver. |
| 1424 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1428 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1425 LookupResult lookup; | 1429 LookupResult lookup; |
| 1426 | 1430 |
| 1427 if (LookupForWrite(*receiver, *name, &lookup)) { | 1431 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1428 bool can_be_inlined = | 1432 bool can_be_inlined = |
| 1429 state == UNINITIALIZED && | 1433 state == UNINITIALIZED && |
| 1430 lookup.IsProperty() && | 1434 lookup.IsProperty() && |
| 1431 lookup.holder() == *receiver && | 1435 lookup.holder() == *receiver && |
| 1432 lookup.type() == FIELD && | 1436 lookup.type() == FIELD && |
| 1433 !receiver->IsAccessCheckNeeded(); | 1437 !receiver->IsAccessCheckNeeded(); |
| 1434 | 1438 |
| 1435 if (can_be_inlined) { | 1439 if (can_be_inlined) { |
| 1436 Map* map = lookup.holder()->map(); | 1440 Map* map = lookup.holder()->map(); |
| 1437 // Property's index in the properties array. If negative we have | 1441 // Property's index in the properties array. If negative we have |
| 1438 // an inobject property. | 1442 // an inobject property. |
| 1439 int index = lookup.GetFieldIndex() - map->inobject_properties(); | 1443 int index = lookup.GetFieldIndex() - map->inobject_properties(); |
| 1440 if (index < 0) { | 1444 if (index < 0) { |
| 1441 // Index is an offset from the end of the object. | 1445 // Index is an offset from the end of the object. |
| 1442 int offset = map->instance_size() + (index * kPointerSize); | 1446 int offset = map->instance_size() + (index * kPointerSize); |
| 1443 if (PatchInlinedStore(address(), map, offset)) { | 1447 if (PatchInlinedStore(address(), map, offset)) { |
| 1444 set_target(megamorphic_stub()); | 1448 set_target((strict_mode == kStrictMode) |
| 1449 ? megamorphic_stub_strict() |
| 1450 : megamorphic_stub()); |
| 1445 #ifdef DEBUG | 1451 #ifdef DEBUG |
| 1446 if (FLAG_trace_ic) { | 1452 if (FLAG_trace_ic) { |
| 1447 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); | 1453 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); |
| 1448 } | 1454 } |
| 1449 #endif | 1455 #endif |
| 1450 return receiver->SetProperty(*name, *value, NONE); | 1456 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1451 #ifdef DEBUG | 1457 #ifdef DEBUG |
| 1452 | 1458 |
| 1453 } else { | 1459 } else { |
| 1454 if (FLAG_trace_ic) { | 1460 if (FLAG_trace_ic) { |
| 1455 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", | 1461 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", |
| 1456 *name->ToCString()); | 1462 *name->ToCString()); |
| 1457 } | 1463 } |
| 1458 } | 1464 } |
| 1459 } else { | 1465 } else { |
| 1460 if (FLAG_trace_ic) { | 1466 if (FLAG_trace_ic) { |
| 1461 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", | 1467 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", |
| 1462 *name->ToCString()); | 1468 *name->ToCString()); |
| 1463 } | 1469 } |
| 1464 } | 1470 } |
| 1465 } else { | 1471 } else { |
| 1466 if (state == PREMONOMORPHIC) { | 1472 if (state == PREMONOMORPHIC) { |
| 1467 if (FLAG_trace_ic) { | 1473 if (FLAG_trace_ic) { |
| 1468 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | 1474 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", |
| 1469 *name->ToCString()); | 1475 *name->ToCString()); |
| 1470 #endif | 1476 #endif |
| 1471 } | 1477 } |
| 1472 } | 1478 } |
| 1473 } | 1479 } |
| 1474 | 1480 |
| 1475 // If no inlined store ic was patched, generate a stub for this | 1481 // If no inlined store ic was patched, generate a stub for this |
| 1476 // store. | 1482 // store. |
| 1477 UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); | 1483 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1478 } else { | 1484 } else { |
| 1479 // Strict mode doesn't allow setting non-existent global property. | 1485 // Strict mode doesn't allow setting non-existent global property |
| 1480 if (extra_ic_state == kStoreICStrict && IsContextual(object)) { | 1486 // or an assignment to a read only property. |
| 1481 return ReferenceError("not_defined", name); | 1487 if (strict_mode == kStrictMode) { |
| 1488 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1489 return TypeError("strict_read_only_property", object, name); |
| 1490 } else if (IsContextual(object)) { |
| 1491 return ReferenceError("not_defined", name); |
| 1492 } |
| 1482 } | 1493 } |
| 1483 } | 1494 } |
| 1484 } | 1495 } |
| 1485 | 1496 |
| 1486 if (receiver->IsJSGlobalProxy()) { | 1497 if (receiver->IsJSGlobalProxy()) { |
| 1487 // Generate a generic stub that goes to the runtime when we see a global | 1498 // Generate a generic stub that goes to the runtime when we see a global |
| 1488 // proxy as receiver. | 1499 // proxy as receiver. |
| 1489 Code* stub = (extra_ic_state == kStoreICStrict) | 1500 Code* stub = (strict_mode == kStrictMode) |
| 1490 ? global_proxy_stub_strict() | 1501 ? global_proxy_stub_strict() |
| 1491 : global_proxy_stub(); | 1502 : global_proxy_stub(); |
| 1492 if (target() != stub) { | 1503 if (target() != stub) { |
| 1493 set_target(stub); | 1504 set_target(stub); |
| 1494 #ifdef DEBUG | 1505 #ifdef DEBUG |
| 1495 TraceIC("StoreIC", name, state, target()); | 1506 TraceIC("StoreIC", name, state, target()); |
| 1496 #endif | 1507 #endif |
| 1497 } | 1508 } |
| 1498 } | 1509 } |
| 1499 | 1510 |
| 1500 // Set the property. | 1511 // Set the property. |
| 1501 return receiver->SetProperty(*name, *value, NONE); | 1512 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1502 } | 1513 } |
| 1503 | 1514 |
| 1504 | 1515 |
| 1505 void StoreIC::UpdateCaches(LookupResult* lookup, | 1516 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1506 State state, | 1517 State state, |
| 1507 Code::ExtraICState extra_ic_state, | 1518 StrictModeFlag strict_mode, |
| 1508 Handle<JSObject> receiver, | 1519 Handle<JSObject> receiver, |
| 1509 Handle<String> name, | 1520 Handle<String> name, |
| 1510 Handle<Object> value) { | 1521 Handle<Object> value) { |
| 1511 // Skip JSGlobalProxy. | 1522 // Skip JSGlobalProxy. |
| 1512 ASSERT(!receiver->IsJSGlobalProxy()); | 1523 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1513 | 1524 |
| 1514 ASSERT(StoreICableLookup(lookup)); | 1525 ASSERT(StoreICableLookup(lookup)); |
| 1515 | 1526 |
| 1516 // If the property has a non-field type allowing map transitions | 1527 // If the property has a non-field type allowing map transitions |
| 1517 // where there is extra room in the object, we leave the IC in its | 1528 // where there is extra room in the object, we leave the IC in its |
| 1518 // current state. | 1529 // current state. |
| 1519 PropertyType type = lookup->type(); | 1530 PropertyType type = lookup->type(); |
| 1520 | 1531 |
| 1521 // Compute the code stub for this store; used for rewriting to | 1532 // Compute the code stub for this store; used for rewriting to |
| 1522 // monomorphic state and making sure that the code stub is in the | 1533 // monomorphic state and making sure that the code stub is in the |
| 1523 // stub cache. | 1534 // stub cache. |
| 1524 MaybeObject* maybe_code = NULL; | 1535 MaybeObject* maybe_code = NULL; |
| 1525 Object* code = NULL; | 1536 Object* code = NULL; |
| 1526 switch (type) { | 1537 switch (type) { |
| 1527 case FIELD: { | 1538 case FIELD: { |
| 1528 maybe_code = StubCache::ComputeStoreField( | 1539 maybe_code = StubCache::ComputeStoreField( |
| 1529 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); | 1540 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1530 break; | 1541 break; |
| 1531 } | 1542 } |
| 1532 case MAP_TRANSITION: { | 1543 case MAP_TRANSITION: { |
| 1533 if (lookup->GetAttributes() != NONE) return; | 1544 if (lookup->GetAttributes() != NONE) return; |
| 1534 HandleScope scope; | 1545 HandleScope scope; |
| 1535 ASSERT(type == MAP_TRANSITION); | 1546 ASSERT(type == MAP_TRANSITION); |
| 1536 Handle<Map> transition(lookup->GetTransitionMap()); | 1547 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1537 int index = transition->PropertyIndexFor(*name); | 1548 int index = transition->PropertyIndexFor(*name); |
| 1538 maybe_code = StubCache::ComputeStoreField( | 1549 maybe_code = StubCache::ComputeStoreField( |
| 1539 *name, *receiver, index, *transition, extra_ic_state); | 1550 *name, *receiver, index, *transition, strict_mode); |
| 1540 break; | 1551 break; |
| 1541 } | 1552 } |
| 1542 case NORMAL: { | 1553 case NORMAL: { |
| 1543 if (receiver->IsGlobalObject()) { | 1554 if (receiver->IsGlobalObject()) { |
| 1544 // The stub generated for the global object picks the value directly | 1555 // The stub generated for the global object picks the value directly |
| 1545 // from the property cell. So the property must be directly on the | 1556 // from the property cell. So the property must be directly on the |
| 1546 // global object. | 1557 // global object. |
| 1547 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1558 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1548 JSGlobalPropertyCell* cell = | 1559 JSGlobalPropertyCell* cell = |
| 1549 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1560 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 1550 maybe_code = StubCache::ComputeStoreGlobal( | 1561 maybe_code = StubCache::ComputeStoreGlobal( |
| 1551 *name, *global, cell, extra_ic_state); | 1562 *name, *global, cell, strict_mode); |
| 1552 } else { | 1563 } else { |
| 1553 if (lookup->holder() != *receiver) return; | 1564 if (lookup->holder() != *receiver) return; |
| 1554 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); | 1565 maybe_code = StubCache::ComputeStoreNormal(strict_mode); |
| 1555 } | 1566 } |
| 1556 break; | 1567 break; |
| 1557 } | 1568 } |
| 1558 case CALLBACKS: { | 1569 case CALLBACKS: { |
| 1559 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1570 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| 1560 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1571 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
| 1561 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1572 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1562 maybe_code = StubCache::ComputeStoreCallback( | 1573 maybe_code = StubCache::ComputeStoreCallback( |
| 1563 *name, *receiver, callback, extra_ic_state); | 1574 *name, *receiver, callback, strict_mode); |
| 1564 break; | 1575 break; |
| 1565 } | 1576 } |
| 1566 case INTERCEPTOR: { | 1577 case INTERCEPTOR: { |
| 1567 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1578 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1568 maybe_code = StubCache::ComputeStoreInterceptor( | 1579 maybe_code = StubCache::ComputeStoreInterceptor( |
| 1569 *name, *receiver, extra_ic_state); | 1580 *name, *receiver, strict_mode); |
| 1570 break; | 1581 break; |
| 1571 } | 1582 } |
| 1572 default: | 1583 default: |
| 1573 return; | 1584 return; |
| 1574 } | 1585 } |
| 1575 | 1586 |
| 1576 // If we're unable to compute the stub (not enough memory left), we | 1587 // If we're unable to compute the stub (not enough memory left), we |
| 1577 // simply avoid updating the caches. | 1588 // simply avoid updating the caches. |
| 1578 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1589 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1579 | 1590 |
| 1580 // Patch the call site depending on the state of the cache. | 1591 // Patch the call site depending on the state of the cache. |
| 1581 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1592 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1582 set_target(Code::cast(code)); | 1593 set_target(Code::cast(code)); |
| 1583 } else if (state == MONOMORPHIC) { | 1594 } else if (state == MONOMORPHIC) { |
| 1584 // Only move to megamorphic if the target changes. | 1595 // Only move to megamorphic if the target changes. |
| 1585 if (target() != Code::cast(code)) { | 1596 if (target() != Code::cast(code)) { |
| 1586 set_target(extra_ic_state == kStoreICStrict | 1597 set_target((strict_mode == kStrictMode) |
| 1587 ? megamorphic_stub_strict() | 1598 ? megamorphic_stub_strict() |
| 1588 : megamorphic_stub()); | 1599 : megamorphic_stub()); |
| 1589 } | 1600 } |
| 1590 } else if (state == MEGAMORPHIC) { | 1601 } else if (state == MEGAMORPHIC) { |
| 1591 // Update the stub cache. | 1602 // Update the stub cache. |
| 1592 StubCache::Set(*name, receiver->map(), Code::cast(code)); | 1603 StubCache::Set(*name, receiver->map(), Code::cast(code)); |
| 1593 } | 1604 } |
| 1594 | 1605 |
| 1595 #ifdef DEBUG | 1606 #ifdef DEBUG |
| 1596 TraceIC("StoreIC", name, state, target()); | 1607 TraceIC("StoreIC", name, state, target()); |
| 1597 #endif | 1608 #endif |
| 1598 } | 1609 } |
| 1599 | 1610 |
| 1600 | 1611 |
| 1601 MaybeObject* KeyedStoreIC::Store(State state, | 1612 MaybeObject* KeyedStoreIC::Store(State state, |
| 1613 StrictModeFlag strict_mode, |
| 1602 Handle<Object> object, | 1614 Handle<Object> object, |
| 1603 Handle<Object> key, | 1615 Handle<Object> key, |
| 1604 Handle<Object> value) { | 1616 Handle<Object> value) { |
| 1605 if (key->IsSymbol()) { | 1617 if (key->IsSymbol()) { |
| 1606 Handle<String> name = Handle<String>::cast(key); | 1618 Handle<String> name = Handle<String>::cast(key); |
| 1607 | 1619 |
| 1608 // If the object is undefined or null it's illegal to try to set any | 1620 // If the object is undefined or null it's illegal to try to set any |
| 1609 // properties on it; throw a TypeError in that case. | 1621 // properties on it; throw a TypeError in that case. |
| 1610 if (object->IsUndefined() || object->IsNull()) { | 1622 if (object->IsUndefined() || object->IsNull()) { |
| 1611 return TypeError("non_object_property_store", object, name); | 1623 return TypeError("non_object_property_store", object, name); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1623 if (result.is_null()) return Failure::Exception(); | 1635 if (result.is_null()) return Failure::Exception(); |
| 1624 return *value; | 1636 return *value; |
| 1625 } | 1637 } |
| 1626 | 1638 |
| 1627 // Lookup the property locally in the receiver. | 1639 // Lookup the property locally in the receiver. |
| 1628 LookupResult lookup; | 1640 LookupResult lookup; |
| 1629 receiver->LocalLookup(*name, &lookup); | 1641 receiver->LocalLookup(*name, &lookup); |
| 1630 | 1642 |
| 1631 // Update inline cache and stub cache. | 1643 // Update inline cache and stub cache. |
| 1632 if (FLAG_use_ic) { | 1644 if (FLAG_use_ic) { |
| 1633 UpdateCaches(&lookup, state, receiver, name, value); | 1645 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1634 } | 1646 } |
| 1635 | 1647 |
| 1636 // Set the property. | 1648 // Set the property. |
| 1637 return receiver->SetProperty(*name, *value, NONE); | 1649 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1638 } | 1650 } |
| 1639 | 1651 |
| 1640 // Do not use ICs for objects that require access checks (including | 1652 // Do not use ICs for objects that require access checks (including |
| 1641 // the global object). | 1653 // the global object). |
| 1642 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1654 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1643 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1655 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1644 | 1656 |
| 1645 if (use_ic) { | 1657 if (use_ic) { |
| 1646 Code* stub = generic_stub(); | 1658 Code* stub = |
| 1659 (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); |
| 1647 if (state == UNINITIALIZED) { | 1660 if (state == UNINITIALIZED) { |
| 1648 if (object->IsJSObject()) { | 1661 if (object->IsJSObject()) { |
| 1649 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1662 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1650 if (receiver->HasExternalArrayElements()) { | 1663 if (receiver->HasExternalArrayElements()) { |
| 1651 MaybeObject* probe = | 1664 MaybeObject* probe = |
| 1652 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); | 1665 StubCache::ComputeKeyedLoadOrStoreExternalArray( |
| 1666 *receiver, true, strict_mode); |
| 1653 stub = probe->IsFailure() ? | 1667 stub = probe->IsFailure() ? |
| 1654 NULL : Code::cast(probe->ToObjectUnchecked()); | 1668 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1655 } else if (receiver->HasPixelElements()) { | 1669 } else if (receiver->HasPixelElements()) { |
| 1656 MaybeObject* probe = | 1670 MaybeObject* probe = |
| 1657 StubCache::ComputeKeyedStorePixelArray(*receiver); | 1671 StubCache::ComputeKeyedStorePixelArray(*receiver, strict_mode); |
| 1658 stub = probe->IsFailure() ? | 1672 stub = probe->IsFailure() ? |
| 1659 NULL : Code::cast(probe->ToObjectUnchecked()); | 1673 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1660 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { | 1674 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { |
| 1661 MaybeObject* probe = | 1675 MaybeObject* probe = |
| 1662 StubCache::ComputeKeyedStoreSpecialized(*receiver); | 1676 StubCache::ComputeKeyedStoreSpecialized(*receiver, strict_mode); |
| 1663 stub = probe->IsFailure() ? | 1677 stub = probe->IsFailure() ? |
| 1664 NULL : Code::cast(probe->ToObjectUnchecked()); | 1678 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1665 } | 1679 } |
| 1666 } | 1680 } |
| 1667 } | 1681 } |
| 1668 if (stub != NULL) set_target(stub); | 1682 if (stub != NULL) set_target(stub); |
| 1669 } | 1683 } |
| 1670 | 1684 |
| 1671 // Set the property. | 1685 // Set the property. |
| 1672 return Runtime::SetObjectProperty(object, key, value, NONE); | 1686 return Runtime::SetObjectProperty(object, key, value, NONE, strict_mode); |
| 1673 } | 1687 } |
| 1674 | 1688 |
| 1675 | 1689 |
| 1676 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1690 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 1677 State state, | 1691 State state, |
| 1692 StrictModeFlag strict_mode, |
| 1678 Handle<JSObject> receiver, | 1693 Handle<JSObject> receiver, |
| 1679 Handle<String> name, | 1694 Handle<String> name, |
| 1680 Handle<Object> value) { | 1695 Handle<Object> value) { |
| 1681 // Skip JSGlobalProxy. | 1696 // Skip JSGlobalProxy. |
| 1682 if (receiver->IsJSGlobalProxy()) return; | 1697 if (receiver->IsJSGlobalProxy()) return; |
| 1683 | 1698 |
| 1684 // Bail out if we didn't find a result. | 1699 // Bail out if we didn't find a result. |
| 1685 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; | 1700 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; |
| 1686 | 1701 |
| 1687 // If the property is read-only, we leave the IC in its current | 1702 // If the property is read-only, we leave the IC in its current |
| 1688 // state. | 1703 // state. |
| 1689 if (lookup->IsReadOnly()) return; | 1704 if (lookup->IsReadOnly()) return; |
| 1690 | 1705 |
| 1691 // If the property has a non-field type allowing map transitions | 1706 // If the property has a non-field type allowing map transitions |
| 1692 // where there is extra room in the object, we leave the IC in its | 1707 // where there is extra room in the object, we leave the IC in its |
| 1693 // current state. | 1708 // current state. |
| 1694 PropertyType type = lookup->type(); | 1709 PropertyType type = lookup->type(); |
| 1695 | 1710 |
| 1696 // Compute the code stub for this store; used for rewriting to | 1711 // Compute the code stub for this store; used for rewriting to |
| 1697 // monomorphic state and making sure that the code stub is in the | 1712 // monomorphic state and making sure that the code stub is in the |
| 1698 // stub cache. | 1713 // stub cache. |
| 1699 MaybeObject* maybe_code = NULL; | 1714 MaybeObject* maybe_code = NULL; |
| 1700 Object* code = NULL; | 1715 Object* code = NULL; |
| 1701 | 1716 |
| 1702 switch (type) { | 1717 switch (type) { |
| 1703 case FIELD: { | 1718 case FIELD: { |
| 1704 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1719 maybe_code = StubCache::ComputeKeyedStoreField( |
| 1705 lookup->GetFieldIndex()); | 1720 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1706 break; | 1721 break; |
| 1707 } | 1722 } |
| 1708 case MAP_TRANSITION: { | 1723 case MAP_TRANSITION: { |
| 1709 if (lookup->GetAttributes() == NONE) { | 1724 if (lookup->GetAttributes() == NONE) { |
| 1710 HandleScope scope; | 1725 HandleScope scope; |
| 1711 ASSERT(type == MAP_TRANSITION); | 1726 ASSERT(type == MAP_TRANSITION); |
| 1712 Handle<Map> transition(lookup->GetTransitionMap()); | 1727 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1713 int index = transition->PropertyIndexFor(*name); | 1728 int index = transition->PropertyIndexFor(*name); |
| 1714 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1729 maybe_code = StubCache::ComputeKeyedStoreField( |
| 1715 index, *transition); | 1730 *name, *receiver, index, *transition, strict_mode); |
| 1716 break; | 1731 break; |
| 1717 } | 1732 } |
| 1718 // fall through. | 1733 // fall through. |
| 1719 } | 1734 } |
| 1720 default: { | 1735 default: { |
| 1721 // Always rewrite to the generic case so that we do not | 1736 // Always rewrite to the generic case so that we do not |
| 1722 // repeatedly try to rewrite. | 1737 // repeatedly try to rewrite. |
| 1723 maybe_code = generic_stub(); | 1738 maybe_code = (strict_mode == kStrictMode) |
| 1739 ? generic_stub_strict() |
| 1740 : generic_stub(); |
| 1724 break; | 1741 break; |
| 1725 } | 1742 } |
| 1726 } | 1743 } |
| 1727 | 1744 |
| 1728 // If we're unable to compute the stub (not enough memory left), we | 1745 // If we're unable to compute the stub (not enough memory left), we |
| 1729 // simply avoid updating the caches. | 1746 // simply avoid updating the caches. |
| 1730 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1747 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1731 | 1748 |
| 1732 // Patch the call site depending on the state of the cache. Make | 1749 // Patch the call site depending on the state of the cache. Make |
| 1733 // sure to always rewrite from monomorphic to megamorphic. | 1750 // sure to always rewrite from monomorphic to megamorphic. |
| 1734 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1751 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
| 1735 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1752 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
| 1736 set_target(Code::cast(code)); | 1753 set_target(Code::cast(code)); |
| 1737 } else if (state == MONOMORPHIC) { | 1754 } else if (state == MONOMORPHIC) { |
| 1738 set_target(megamorphic_stub()); | 1755 set_target((strict_mode == kStrictMode) |
| 1756 ? megamorphic_stub_strict() |
| 1757 : megamorphic_stub()); |
| 1739 } | 1758 } |
| 1740 | 1759 |
| 1741 #ifdef DEBUG | 1760 #ifdef DEBUG |
| 1742 TraceIC("KeyedStoreIC", name, state, target()); | 1761 TraceIC("KeyedStoreIC", name, state, target()); |
| 1743 #endif | 1762 #endif |
| 1744 } | 1763 } |
| 1745 | 1764 |
| 1746 | 1765 |
| 1747 // ---------------------------------------------------------------------------- | 1766 // ---------------------------------------------------------------------------- |
| 1748 // Static IC stub generators. | 1767 // Static IC stub generators. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1829 } | 1848 } |
| 1830 | 1849 |
| 1831 | 1850 |
| 1832 // Used from ic-<arch>.cc. | 1851 // Used from ic-<arch>.cc. |
| 1833 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { | 1852 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { |
| 1834 NoHandleAllocation na; | 1853 NoHandleAllocation na; |
| 1835 ASSERT(args.length() == 3); | 1854 ASSERT(args.length() == 3); |
| 1836 StoreIC ic; | 1855 StoreIC ic; |
| 1837 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1856 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1838 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1857 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1839 return ic.Store(state, extra_ic_state, args.at<Object>(0), | 1858 return ic.Store(state, |
| 1840 args.at<String>(1), args.at<Object>(2)); | 1859 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1860 args.at<Object>(0), |
| 1861 args.at<String>(1), |
| 1862 args.at<Object>(2)); |
| 1841 } | 1863 } |
| 1842 | 1864 |
| 1843 | 1865 |
| 1844 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { | 1866 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { |
| 1845 NoHandleAllocation nha; | 1867 NoHandleAllocation nha; |
| 1846 | 1868 |
| 1847 ASSERT(args.length() == 2); | 1869 ASSERT(args.length() == 2); |
| 1848 JSObject* receiver = JSObject::cast(args[0]); | 1870 JSObject* receiver = JSObject::cast(args[0]); |
| 1849 Object* len = args[1]; | 1871 Object* len = args[1]; |
| 1850 | 1872 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1894 return value; | 1916 return value; |
| 1895 } | 1917 } |
| 1896 | 1918 |
| 1897 | 1919 |
| 1898 // Used from ic-<arch>.cc. | 1920 // Used from ic-<arch>.cc. |
| 1899 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { | 1921 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { |
| 1900 NoHandleAllocation na; | 1922 NoHandleAllocation na; |
| 1901 ASSERT(args.length() == 3); | 1923 ASSERT(args.length() == 3); |
| 1902 KeyedStoreIC ic; | 1924 KeyedStoreIC ic; |
| 1903 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1925 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1904 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1926 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1927 return ic.Store(state, |
| 1928 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1929 args.at<Object>(0), |
| 1930 args.at<Object>(1), |
| 1905 args.at<Object>(2)); | 1931 args.at<Object>(2)); |
| 1906 } | 1932 } |
| 1907 | 1933 |
| 1908 | 1934 |
| 1909 void BinaryOpIC::patch(Code* code) { | 1935 void BinaryOpIC::patch(Code* code) { |
| 1910 set_target(code); | 1936 set_target(code); |
| 1911 } | 1937 } |
| 1912 | 1938 |
| 1913 | 1939 |
| 1914 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 1940 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2298 #undef ADDR | 2324 #undef ADDR |
| 2299 }; | 2325 }; |
| 2300 | 2326 |
| 2301 | 2327 |
| 2302 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2328 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2303 return IC_utilities[id]; | 2329 return IC_utilities[id]; |
| 2304 } | 2330 } |
| 2305 | 2331 |
| 2306 | 2332 |
| 2307 } } // namespace v8::internal | 2333 } } // namespace v8::internal |
| OLD | NEW |