Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/ic.cc

Issue 6576024: (early draft) Strict mode - throw exception on assignment to read only property. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Assign to read only property in strict mode. Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/ic-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/ic-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698