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 |