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 if (strict_mode == kStrictMode) { |
1481 return ReferenceError("not_defined", name); | 1487 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1488 return TypeError("strict_rdonly_property", object, name); |
| 1489 } else if (IsContextual(object)) { |
| 1490 return ReferenceError("not_defined", name); |
| 1491 } |
1482 } | 1492 } |
1483 } | 1493 } |
1484 } | 1494 } |
1485 | 1495 |
1486 if (receiver->IsJSGlobalProxy()) { | 1496 if (receiver->IsJSGlobalProxy()) { |
1487 // Generate a generic stub that goes to the runtime when we see a global | 1497 // Generate a generic stub that goes to the runtime when we see a global |
1488 // proxy as receiver. | 1498 // proxy as receiver. |
1489 Code* stub = (extra_ic_state == kStoreICStrict) | 1499 Code* stub = (strict_mode == kStrictMode) |
1490 ? global_proxy_stub_strict() | 1500 ? global_proxy_stub_strict() |
1491 : global_proxy_stub(); | 1501 : global_proxy_stub(); |
1492 if (target() != stub) { | 1502 if (target() != stub) { |
1493 set_target(stub); | 1503 set_target(stub); |
1494 #ifdef DEBUG | 1504 #ifdef DEBUG |
1495 TraceIC("StoreIC", name, state, target()); | 1505 TraceIC("StoreIC", name, state, target()); |
1496 #endif | 1506 #endif |
1497 } | 1507 } |
1498 } | 1508 } |
1499 | 1509 |
1500 // Set the property. | 1510 // Set the property. |
1501 return receiver->SetProperty(*name, *value, NONE); | 1511 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1502 } | 1512 } |
1503 | 1513 |
1504 | 1514 |
1505 void StoreIC::UpdateCaches(LookupResult* lookup, | 1515 void StoreIC::UpdateCaches(LookupResult* lookup, |
1506 State state, | 1516 State state, |
1507 Code::ExtraICState extra_ic_state, | 1517 StrictModeFlag strict_mode, |
1508 Handle<JSObject> receiver, | 1518 Handle<JSObject> receiver, |
1509 Handle<String> name, | 1519 Handle<String> name, |
1510 Handle<Object> value) { | 1520 Handle<Object> value) { |
1511 // Skip JSGlobalProxy. | 1521 // Skip JSGlobalProxy. |
1512 ASSERT(!receiver->IsJSGlobalProxy()); | 1522 ASSERT(!receiver->IsJSGlobalProxy()); |
1513 | 1523 |
1514 ASSERT(StoreICableLookup(lookup)); | 1524 ASSERT(StoreICableLookup(lookup)); |
1515 | 1525 |
1516 // If the property has a non-field type allowing map transitions | 1526 // 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 | 1527 // where there is extra room in the object, we leave the IC in its |
1518 // current state. | 1528 // current state. |
1519 PropertyType type = lookup->type(); | 1529 PropertyType type = lookup->type(); |
1520 | 1530 |
1521 // Compute the code stub for this store; used for rewriting to | 1531 // Compute the code stub for this store; used for rewriting to |
1522 // monomorphic state and making sure that the code stub is in the | 1532 // monomorphic state and making sure that the code stub is in the |
1523 // stub cache. | 1533 // stub cache. |
1524 MaybeObject* maybe_code = NULL; | 1534 MaybeObject* maybe_code = NULL; |
1525 Object* code = NULL; | 1535 Object* code = NULL; |
1526 switch (type) { | 1536 switch (type) { |
1527 case FIELD: { | 1537 case FIELD: { |
1528 maybe_code = StubCache::ComputeStoreField( | 1538 maybe_code = StubCache::ComputeStoreField( |
1529 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); | 1539 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
1530 break; | 1540 break; |
1531 } | 1541 } |
1532 case MAP_TRANSITION: { | 1542 case MAP_TRANSITION: { |
1533 if (lookup->GetAttributes() != NONE) return; | 1543 if (lookup->GetAttributes() != NONE) return; |
1534 HandleScope scope; | 1544 HandleScope scope; |
1535 ASSERT(type == MAP_TRANSITION); | 1545 ASSERT(type == MAP_TRANSITION); |
1536 Handle<Map> transition(lookup->GetTransitionMap()); | 1546 Handle<Map> transition(lookup->GetTransitionMap()); |
1537 int index = transition->PropertyIndexFor(*name); | 1547 int index = transition->PropertyIndexFor(*name); |
1538 maybe_code = StubCache::ComputeStoreField( | 1548 maybe_code = StubCache::ComputeStoreField( |
1539 *name, *receiver, index, *transition, extra_ic_state); | 1549 *name, *receiver, index, *transition, strict_mode); |
1540 break; | 1550 break; |
1541 } | 1551 } |
1542 case NORMAL: { | 1552 case NORMAL: { |
1543 if (receiver->IsGlobalObject()) { | 1553 if (receiver->IsGlobalObject()) { |
1544 // The stub generated for the global object picks the value directly | 1554 // The stub generated for the global object picks the value directly |
1545 // from the property cell. So the property must be directly on the | 1555 // from the property cell. So the property must be directly on the |
1546 // global object. | 1556 // global object. |
1547 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1557 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
1548 JSGlobalPropertyCell* cell = | 1558 JSGlobalPropertyCell* cell = |
1549 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1559 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
1550 maybe_code = StubCache::ComputeStoreGlobal( | 1560 maybe_code = StubCache::ComputeStoreGlobal( |
1551 *name, *global, cell, extra_ic_state); | 1561 *name, *global, cell, strict_mode); |
1552 } else { | 1562 } else { |
1553 if (lookup->holder() != *receiver) return; | 1563 if (lookup->holder() != *receiver) return; |
1554 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); | 1564 maybe_code = StubCache::ComputeStoreNormal(strict_mode); |
1555 } | 1565 } |
1556 break; | 1566 break; |
1557 } | 1567 } |
1558 case CALLBACKS: { | 1568 case CALLBACKS: { |
1559 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1569 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
1560 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1570 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
1561 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1571 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
1562 maybe_code = StubCache::ComputeStoreCallback( | 1572 maybe_code = StubCache::ComputeStoreCallback( |
1563 *name, *receiver, callback, extra_ic_state); | 1573 *name, *receiver, callback, strict_mode); |
1564 break; | 1574 break; |
1565 } | 1575 } |
1566 case INTERCEPTOR: { | 1576 case INTERCEPTOR: { |
1567 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1577 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
1568 maybe_code = StubCache::ComputeStoreInterceptor( | 1578 maybe_code = StubCache::ComputeStoreInterceptor( |
1569 *name, *receiver, extra_ic_state); | 1579 *name, *receiver, strict_mode); |
1570 break; | 1580 break; |
1571 } | 1581 } |
1572 default: | 1582 default: |
1573 return; | 1583 return; |
1574 } | 1584 } |
1575 | 1585 |
1576 // If we're unable to compute the stub (not enough memory left), we | 1586 // If we're unable to compute the stub (not enough memory left), we |
1577 // simply avoid updating the caches. | 1587 // simply avoid updating the caches. |
1578 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1588 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
1579 | 1589 |
1580 // Patch the call site depending on the state of the cache. | 1590 // Patch the call site depending on the state of the cache. |
1581 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1591 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
1582 set_target(Code::cast(code)); | 1592 set_target(Code::cast(code)); |
1583 } else if (state == MONOMORPHIC) { | 1593 } else if (state == MONOMORPHIC) { |
1584 // Only move to megamorphic if the target changes. | 1594 // Only move to megamorphic if the target changes. |
1585 if (target() != Code::cast(code)) { | 1595 if (target() != Code::cast(code)) { |
1586 set_target(extra_ic_state == kStoreICStrict | 1596 set_target(strict_mode == kStrictMode |
1587 ? megamorphic_stub_strict() | 1597 ? megamorphic_stub_strict() |
1588 : megamorphic_stub()); | 1598 : megamorphic_stub()); |
1589 } | 1599 } |
1590 } else if (state == MEGAMORPHIC) { | 1600 } else if (state == MEGAMORPHIC) { |
1591 // Update the stub cache. | 1601 // Update the stub cache. |
1592 StubCache::Set(*name, receiver->map(), Code::cast(code)); | 1602 StubCache::Set(*name, receiver->map(), Code::cast(code)); |
1593 } | 1603 } |
1594 | 1604 |
1595 #ifdef DEBUG | 1605 #ifdef DEBUG |
1596 TraceIC("StoreIC", name, state, target()); | 1606 TraceIC("StoreIC", name, state, target()); |
1597 #endif | 1607 #endif |
1598 } | 1608 } |
1599 | 1609 |
1600 | 1610 |
1601 MaybeObject* KeyedStoreIC::Store(State state, | 1611 MaybeObject* KeyedStoreIC::Store(State state, |
| 1612 StrictModeFlag strict_mode, |
1602 Handle<Object> object, | 1613 Handle<Object> object, |
1603 Handle<Object> key, | 1614 Handle<Object> key, |
1604 Handle<Object> value) { | 1615 Handle<Object> value) { |
1605 if (key->IsSymbol()) { | 1616 if (key->IsSymbol()) { |
1606 Handle<String> name = Handle<String>::cast(key); | 1617 Handle<String> name = Handle<String>::cast(key); |
1607 | 1618 |
1608 // If the object is undefined or null it's illegal to try to set any | 1619 // 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. | 1620 // properties on it; throw a TypeError in that case. |
1610 if (object->IsUndefined() || object->IsNull()) { | 1621 if (object->IsUndefined() || object->IsNull()) { |
1611 return TypeError("non_object_property_store", object, name); | 1622 return TypeError("non_object_property_store", object, name); |
(...skipping 11 matching lines...) Expand all Loading... |
1623 if (result.is_null()) return Failure::Exception(); | 1634 if (result.is_null()) return Failure::Exception(); |
1624 return *value; | 1635 return *value; |
1625 } | 1636 } |
1626 | 1637 |
1627 // Lookup the property locally in the receiver. | 1638 // Lookup the property locally in the receiver. |
1628 LookupResult lookup; | 1639 LookupResult lookup; |
1629 receiver->LocalLookup(*name, &lookup); | 1640 receiver->LocalLookup(*name, &lookup); |
1630 | 1641 |
1631 // Update inline cache and stub cache. | 1642 // Update inline cache and stub cache. |
1632 if (FLAG_use_ic) { | 1643 if (FLAG_use_ic) { |
1633 UpdateCaches(&lookup, state, receiver, name, value); | 1644 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
1634 } | 1645 } |
1635 | 1646 |
1636 // Set the property. | 1647 // Set the property. |
1637 return receiver->SetProperty(*name, *value, NONE); | 1648 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1638 } | 1649 } |
1639 | 1650 |
1640 // Do not use ICs for objects that require access checks (including | 1651 // Do not use ICs for objects that require access checks (including |
1641 // the global object). | 1652 // the global object). |
1642 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1653 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1643 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1654 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
1644 | 1655 |
1645 if (use_ic) { | 1656 if (use_ic) { |
1646 Code* stub = generic_stub(); | 1657 Code* stub = |
| 1658 strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); |
1647 if (state == UNINITIALIZED) { | 1659 if (state == UNINITIALIZED) { |
1648 if (object->IsJSObject()) { | 1660 if (object->IsJSObject()) { |
1649 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1661 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1650 if (receiver->HasExternalArrayElements()) { | 1662 if (receiver->HasExternalArrayElements()) { |
1651 MaybeObject* probe = | 1663 MaybeObject* probe = |
1652 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); | 1664 StubCache::ComputeKeyedLoadOrStoreExternalArray( |
| 1665 *receiver, true, strict_mode); |
1653 stub = probe->IsFailure() ? | 1666 stub = probe->IsFailure() ? |
1654 NULL : Code::cast(probe->ToObjectUnchecked()); | 1667 NULL : Code::cast(probe->ToObjectUnchecked()); |
1655 } else if (receiver->HasPixelElements()) { | 1668 } else if (receiver->HasPixelElements()) { |
1656 MaybeObject* probe = | 1669 MaybeObject* probe = |
1657 StubCache::ComputeKeyedStorePixelArray(*receiver); | 1670 StubCache::ComputeKeyedStorePixelArray(*receiver, strict_mode); |
1658 stub = probe->IsFailure() ? | 1671 stub = probe->IsFailure() ? |
1659 NULL : Code::cast(probe->ToObjectUnchecked()); | 1672 NULL : Code::cast(probe->ToObjectUnchecked()); |
1660 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { | 1673 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { |
1661 MaybeObject* probe = | 1674 MaybeObject* probe = |
1662 StubCache::ComputeKeyedStoreSpecialized(*receiver); | 1675 StubCache::ComputeKeyedStoreSpecialized(*receiver, strict_mode); |
1663 stub = probe->IsFailure() ? | 1676 stub = probe->IsFailure() ? |
1664 NULL : Code::cast(probe->ToObjectUnchecked()); | 1677 NULL : Code::cast(probe->ToObjectUnchecked()); |
1665 } | 1678 } |
1666 } | 1679 } |
1667 } | 1680 } |
1668 if (stub != NULL) set_target(stub); | 1681 if (stub != NULL) set_target(stub); |
1669 } | 1682 } |
1670 | 1683 |
1671 // Set the property. | 1684 // Set the property. |
1672 return Runtime::SetObjectProperty(object, key, value, NONE); | 1685 return Runtime::SetObjectProperty(object, key, value, NONE, strict_mode); |
1673 } | 1686 } |
1674 | 1687 |
1675 | 1688 |
1676 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1689 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
1677 State state, | 1690 State state, |
| 1691 StrictModeFlag strict_mode, |
1678 Handle<JSObject> receiver, | 1692 Handle<JSObject> receiver, |
1679 Handle<String> name, | 1693 Handle<String> name, |
1680 Handle<Object> value) { | 1694 Handle<Object> value) { |
1681 // Skip JSGlobalProxy. | 1695 // Skip JSGlobalProxy. |
1682 if (receiver->IsJSGlobalProxy()) return; | 1696 if (receiver->IsJSGlobalProxy()) return; |
1683 | 1697 |
1684 // Bail out if we didn't find a result. | 1698 // Bail out if we didn't find a result. |
1685 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; | 1699 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; |
1686 | 1700 |
1687 // If the property is read-only, we leave the IC in its current | 1701 // If the property is read-only, we leave the IC in its current |
1688 // state. | 1702 // state. |
1689 if (lookup->IsReadOnly()) return; | 1703 if (lookup->IsReadOnly()) return; |
1690 | 1704 |
1691 // If the property has a non-field type allowing map transitions | 1705 // 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 | 1706 // where there is extra room in the object, we leave the IC in its |
1693 // current state. | 1707 // current state. |
1694 PropertyType type = lookup->type(); | 1708 PropertyType type = lookup->type(); |
1695 | 1709 |
1696 // Compute the code stub for this store; used for rewriting to | 1710 // Compute the code stub for this store; used for rewriting to |
1697 // monomorphic state and making sure that the code stub is in the | 1711 // monomorphic state and making sure that the code stub is in the |
1698 // stub cache. | 1712 // stub cache. |
1699 MaybeObject* maybe_code = NULL; | 1713 MaybeObject* maybe_code = NULL; |
1700 Object* code = NULL; | 1714 Object* code = NULL; |
1701 | 1715 |
1702 switch (type) { | 1716 switch (type) { |
1703 case FIELD: { | 1717 case FIELD: { |
1704 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1718 maybe_code = StubCache::ComputeKeyedStoreField( |
1705 lookup->GetFieldIndex()); | 1719 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
1706 break; | 1720 break; |
1707 } | 1721 } |
1708 case MAP_TRANSITION: { | 1722 case MAP_TRANSITION: { |
1709 if (lookup->GetAttributes() == NONE) { | 1723 if (lookup->GetAttributes() == NONE) { |
1710 HandleScope scope; | 1724 HandleScope scope; |
1711 ASSERT(type == MAP_TRANSITION); | 1725 ASSERT(type == MAP_TRANSITION); |
1712 Handle<Map> transition(lookup->GetTransitionMap()); | 1726 Handle<Map> transition(lookup->GetTransitionMap()); |
1713 int index = transition->PropertyIndexFor(*name); | 1727 int index = transition->PropertyIndexFor(*name); |
1714 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1728 maybe_code = StubCache::ComputeKeyedStoreField( |
1715 index, *transition); | 1729 *name, *receiver, index, *transition, strict_mode); |
1716 break; | 1730 break; |
1717 } | 1731 } |
1718 // fall through. | 1732 // fall through. |
1719 } | 1733 } |
1720 default: { | 1734 default: { |
1721 // Always rewrite to the generic case so that we do not | 1735 // Always rewrite to the generic case so that we do not |
1722 // repeatedly try to rewrite. | 1736 // repeatedly try to rewrite. |
1723 maybe_code = generic_stub(); | 1737 maybe_code = strict_mode == kStrictMode |
| 1738 ? generic_stub_strict() |
| 1739 : generic_stub(); |
1724 break; | 1740 break; |
1725 } | 1741 } |
1726 } | 1742 } |
1727 | 1743 |
1728 // If we're unable to compute the stub (not enough memory left), we | 1744 // If we're unable to compute the stub (not enough memory left), we |
1729 // simply avoid updating the caches. | 1745 // simply avoid updating the caches. |
1730 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1746 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
1731 | 1747 |
1732 // Patch the call site depending on the state of the cache. Make | 1748 // Patch the call site depending on the state of the cache. Make |
1733 // sure to always rewrite from monomorphic to megamorphic. | 1749 // sure to always rewrite from monomorphic to megamorphic. |
1734 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1750 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
1735 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1751 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
1736 set_target(Code::cast(code)); | 1752 set_target(Code::cast(code)); |
1737 } else if (state == MONOMORPHIC) { | 1753 } else if (state == MONOMORPHIC) { |
1738 set_target(megamorphic_stub()); | 1754 set_target(strict_mode == kStrictMode |
| 1755 ? megamorphic_stub_strict() |
| 1756 : megamorphic_stub()); |
1739 } | 1757 } |
1740 | 1758 |
1741 #ifdef DEBUG | 1759 #ifdef DEBUG |
1742 TraceIC("KeyedStoreIC", name, state, target()); | 1760 TraceIC("KeyedStoreIC", name, state, target()); |
1743 #endif | 1761 #endif |
1744 } | 1762 } |
1745 | 1763 |
1746 | 1764 |
1747 // ---------------------------------------------------------------------------- | 1765 // ---------------------------------------------------------------------------- |
1748 // Static IC stub generators. | 1766 // Static IC stub generators. |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1829 } | 1847 } |
1830 | 1848 |
1831 | 1849 |
1832 // Used from ic-<arch>.cc. | 1850 // Used from ic-<arch>.cc. |
1833 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { | 1851 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { |
1834 NoHandleAllocation na; | 1852 NoHandleAllocation na; |
1835 ASSERT(args.length() == 3); | 1853 ASSERT(args.length() == 3); |
1836 StoreIC ic; | 1854 StoreIC ic; |
1837 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1855 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
1838 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1856 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
1839 return ic.Store(state, extra_ic_state, args.at<Object>(0), | 1857 ASSERT(extra_ic_state == kStrictMode || extra_ic_state == kNonStrictMode); |
1840 args.at<String>(1), args.at<Object>(2)); | 1858 MaybeObject* result = ic.Store(state, |
| 1859 static_cast<StrictModeFlag>(extra_ic_state), |
| 1860 args.at<Object>(0), |
| 1861 args.at<String>(1), |
| 1862 args.at<Object>(2)); |
| 1863 // If this assert triggers the IC strict mode was changed. |
| 1864 // The strict mode flag must be preserved on the IC. |
| 1865 // |
| 1866 // ic.target() doesn't appear to be valid in some cases when exiting from |
| 1867 // ic.Store. Could it be crankshaft OSR? |
| 1868 // |
| 1869 // ASSERT(extra_ic_state == ic.target()->extra_ic_state()); |
| 1870 return result; |
1841 } | 1871 } |
1842 | 1872 |
1843 | 1873 |
1844 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { | 1874 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { |
1845 NoHandleAllocation nha; | 1875 NoHandleAllocation nha; |
1846 | 1876 |
1847 ASSERT(args.length() == 2); | 1877 ASSERT(args.length() == 2); |
1848 JSObject* receiver = JSObject::cast(args[0]); | 1878 JSObject* receiver = JSObject::cast(args[0]); |
1849 Object* len = args[1]; | 1879 Object* len = args[1]; |
1850 | 1880 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1894 return value; | 1924 return value; |
1895 } | 1925 } |
1896 | 1926 |
1897 | 1927 |
1898 // Used from ic-<arch>.cc. | 1928 // Used from ic-<arch>.cc. |
1899 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { | 1929 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { |
1900 NoHandleAllocation na; | 1930 NoHandleAllocation na; |
1901 ASSERT(args.length() == 3); | 1931 ASSERT(args.length() == 3); |
1902 KeyedStoreIC ic; | 1932 KeyedStoreIC ic; |
1903 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1933 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
1904 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1934 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
1905 args.at<Object>(2)); | 1935 ASSERT(extra_ic_state == kStrictMode || extra_ic_state == kNonStrictMode); |
| 1936 MaybeObject* result = ic.Store(state, |
| 1937 static_cast<StrictModeFlag>(extra_ic_state), |
| 1938 args.at<Object>(0), |
| 1939 args.at<Object>(1), |
| 1940 args.at<Object>(2)); |
| 1941 // If this assert triggers the IC strict mode was changed. |
| 1942 // The strict mode flag must be preserved on the IC. |
| 1943 // |
| 1944 // ic.target() doesn't appear to be valid in some cases when exiting from |
| 1945 // ic.Store. Could it be crankshaft OSR? |
| 1946 // |
| 1947 // ASSERT(extra_ic_state == ic.target()->extra_ic_state()); |
| 1948 return result; |
1906 } | 1949 } |
1907 | 1950 |
1908 | 1951 |
1909 void BinaryOpIC::patch(Code* code) { | 1952 void BinaryOpIC::patch(Code* code) { |
1910 set_target(code); | 1953 set_target(code); |
1911 } | 1954 } |
1912 | 1955 |
1913 | 1956 |
1914 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 1957 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
1915 switch (type_info) { | 1958 switch (type_info) { |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2298 #undef ADDR | 2341 #undef ADDR |
2299 }; | 2342 }; |
2300 | 2343 |
2301 | 2344 |
2302 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2345 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2303 return IC_utilities[id]; | 2346 return IC_utilities[id]; |
2304 } | 2347 } |
2305 | 2348 |
2306 | 2349 |
2307 } } // namespace v8::internal | 2350 } } // namespace v8::internal |
OLD | NEW |