OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <memory> | 9 #include <memory> |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 7403 matching lines...) Loading... | |
7414 } | 7414 } |
7415 | 7415 |
7416 | 7416 |
7417 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, | 7417 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, |
7418 IntegrityLevel level, | 7418 IntegrityLevel level, |
7419 ShouldThrow should_throw) { | 7419 ShouldThrow should_throw) { |
7420 DCHECK(level == SEALED || level == FROZEN); | 7420 DCHECK(level == SEALED || level == FROZEN); |
7421 | 7421 |
7422 if (receiver->IsJSObject()) { | 7422 if (receiver->IsJSObject()) { |
7423 Handle<JSObject> object = Handle<JSObject>::cast(receiver); | 7423 Handle<JSObject> object = Handle<JSObject>::cast(receiver); |
7424 | |
7425 // prevent memory leaks by not adding unnecessary transitions | |
7426 Maybe<bool> test = JSObject::TestIntegrityLevel(object, level); | |
7427 MAYBE_RETURN(test, Nothing<bool>()); | |
7428 if (test.FromJust()) return Just(true); | |
7429 | |
7424 if (!object->HasSloppyArgumentsElements()) { // Fast path. | 7430 if (!object->HasSloppyArgumentsElements()) { // Fast path. |
7425 if (level == SEALED) { | 7431 if (level == SEALED) { |
7426 return JSObject::PreventExtensionsWithTransition<SEALED>(object, | 7432 return JSObject::PreventExtensionsWithTransition<SEALED>(object, |
7427 should_throw); | 7433 should_throw); |
7428 } else { | 7434 } else { |
7429 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, | 7435 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, |
7430 should_throw); | 7436 should_throw); |
7431 } | 7437 } |
7432 } | 7438 } |
7433 } | 7439 } |
(...skipping 36 matching lines...) Loading... | |
7470 ? no_conf | 7476 ? no_conf |
7471 : no_conf_no_write; | 7477 : no_conf_no_write; |
7472 MAYBE_RETURN( | 7478 MAYBE_RETURN( |
7473 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR), | 7479 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR), |
7474 Nothing<bool>()); | 7480 Nothing<bool>()); |
7475 } | 7481 } |
7476 } | 7482 } |
7477 return Just(true); | 7483 return Just(true); |
7478 } | 7484 } |
7479 | 7485 |
7480 | 7486 namespace { |
7481 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object, | 7487 Maybe<bool> GenericTestDescriptorsIntegrity(Handle<JSReceiver> object, |
7482 IntegrityLevel level) { | 7488 PropertyAttributes level) { |
7483 DCHECK(level == SEALED || level == FROZEN); | |
7484 Isolate* isolate = object->GetIsolate(); | 7489 Isolate* isolate = object->GetIsolate(); |
7485 | 7490 |
7486 Maybe<bool> extensible = JSReceiver::IsExtensible(object); | |
7487 MAYBE_RETURN(extensible, Nothing<bool>()); | |
7488 if (extensible.FromJust()) return Just(false); | |
7489 | |
7490 Handle<FixedArray> keys; | 7491 Handle<FixedArray> keys; |
7491 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 7492 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
7492 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>()); | 7493 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>()); |
7493 | 7494 |
7494 for (int i = 0; i < keys->length(); ++i) { | 7495 for (int i = 0; i < keys->length(); ++i) { |
7495 Handle<Object> key(keys->get(i), isolate); | 7496 Handle<Object> key(keys->get(i), isolate); |
7496 PropertyDescriptor current_desc; | 7497 PropertyDescriptor current_desc; |
7497 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( | 7498 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( |
7498 isolate, object, key, ¤t_desc); | 7499 isolate, object, key, ¤t_desc); |
7499 MAYBE_RETURN(owned, Nothing<bool>()); | 7500 MAYBE_RETURN(owned, Nothing<bool>()); |
7500 if (owned.FromJust()) { | 7501 if (owned.FromJust()) { |
7501 if (current_desc.configurable()) return Just(false); | 7502 if (current_desc.configurable()) return Just(false); |
7502 if (level == FROZEN && | 7503 if (level == FROZEN && |
7503 PropertyDescriptor::IsDataDescriptor(¤t_desc) && | 7504 PropertyDescriptor::IsDataDescriptor(¤t_desc) && |
7504 current_desc.writable()) { | 7505 current_desc.writable()) { |
7505 return Just(false); | 7506 return Just(false); |
7506 } | 7507 } |
7507 } | 7508 } |
7508 } | 7509 } |
7509 return Just(true); | 7510 return Just(true); |
7510 } | 7511 } |
7511 | 7512 |
7513 template <typename Dictionary> | |
7514 bool TestDictionaryPropertyIntegrity(Dictionary dict, Isolate* isolate, | |
7515 PropertyAttributes level) { | |
7516 DisallowHeapAllocation no_gc; | |
7517 uint32_t capacity = dict->Capacity(); | |
7518 FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, { | |
Toon Verwaest
2017/06/20 08:43:23
Since you don't create handles here you don't need
kris.selden
2017/06/20 19:16:21
sorry, that was a bit of copy & paste from some ot
| |
7519 Object* k = dict->KeyAt(j); | |
7520 if (!dict->IsKey(isolate, k)) continue; | |
Toon Verwaest
2017/06/20 08:43:23
You also need to check whether the key is "deleted
| |
7521 PropertyDetails details = dict->DetailsAt(j); | |
7522 if (details.IsConfigurable()) return false; | |
7523 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) { | |
7524 return false; | |
7525 } | |
7526 }); | |
7527 return true; | |
7528 } | |
7529 | |
7530 bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) { | |
7531 ElementsKind kind = object->GetElementsKind(); | |
7532 | |
7533 DCHECK(!IsSloppyArgumentsElementsKind(kind)); | |
7534 | |
7535 if (IsDictionaryElementsKind(kind)) { | |
7536 return TestDictionaryPropertyIntegrity( | |
7537 SeededNumberDictionary::cast(object->elements()), object->GetIsolate(), | |
7538 level); | |
7539 } | |
7540 | |
7541 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); | |
7542 // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have | |
7543 // PropertyAttributes so just test if empty | |
7544 return accessor->NumberOfElements(object) == 0; | |
7545 } | |
7546 | |
7547 bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) { | |
7548 DescriptorArray* descriptors = map->instance_descriptors(); | |
7549 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); | |
7550 for (int i = 0; i < number_of_own_descriptors; i++) { | |
7551 PropertyDetails details = descriptors->GetDetails(i); | |
7552 if (details.IsConfigurable()) return false; | |
7553 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) { | |
7554 return false; | |
7555 } | |
7556 } | |
7557 return true; | |
7558 } | |
7559 | |
7560 bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) { | |
7561 if (object->HasFastProperties()) { | |
7562 return TestFastPropertiesIntegrityLevel(object->map(), level); | |
7563 } | |
7564 | |
7565 if (object->IsJSGlobalObject()) { | |
7566 return TestDictionaryPropertyIntegrity(object->global_dictionary(), | |
7567 object->GetIsolate(), level); | |
7568 } | |
7569 | |
7570 return TestDictionaryPropertyIntegrity(object->property_dictionary(), | |
7571 object->GetIsolate(), level); | |
7572 } | |
7573 | |
7574 } // namespace | |
7575 | |
7576 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object, | |
7577 IntegrityLevel level) { | |
7578 if (object->IsJSObject()) { | |
Toon Verwaest
2017/06/20 08:43:23
object->instance_type() > LAST_CUSTOM_ELEMENTS_REC
| |
7579 return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(object), level); | |
7580 } | |
7581 | |
7582 DCHECK(level == SEALED || level == FROZEN); | |
7583 | |
7584 Maybe<bool> extensible = JSReceiver::IsExtensible(object); | |
7585 MAYBE_RETURN(extensible, Nothing<bool>()); | |
7586 if (extensible.FromJust()) return Just(false); | |
7587 | |
7588 return GenericTestDescriptorsIntegrity(object, level); | |
7589 } | |
7590 | |
7591 Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object, | |
7592 IntegrityLevel level) { | |
7593 DCHECK(level == SEALED || level == FROZEN); | |
7594 | |
7595 Isolate* isolate = object->GetIsolate(); | |
7596 if (object->IsAccessCheckNeeded() && | |
Toon Verwaest
2017/06/20 08:43:23
If you only support > LAST_CUSTOM_ELEMENTS_RECEIVE
| |
7597 !isolate->MayAccess(handle(isolate->context()), object)) { | |
7598 return Just(false); | |
7599 } | |
7600 | |
7601 if (object->IsJSGlobalProxy()) { | |
Toon Verwaest
2017/06/20 08:43:23
And in that case you can also drop this.
| |
7602 PrototypeIterator iter(isolate, object); | |
7603 if (iter.IsAtEnd()) return Just(true); | |
7604 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | |
7605 return TestIntegrityLevel(PrototypeIterator::GetCurrent<JSObject>(iter), | |
7606 level); | |
7607 } | |
7608 | |
7609 if (object->map()->is_extensible()) return Just(false); | |
7610 | |
7611 if (object->HasSloppyArgumentsElements()) { | |
7612 return GenericTestDescriptorsIntegrity(Handle<JSReceiver>::cast(object), | |
7613 level); | |
7614 } | |
7615 | |
7616 if (!TestElementsIntegrityLevel(*object, level)) { | |
Toon Verwaest
2017/06/20 08:43:23
return Just(!object->map()->is_extensible() &&
| |
7617 return Just(false); | |
7618 } | |
7619 | |
7620 if (!TestPropertiesIntegrityLevel(*object, level)) { | |
7621 return Just(false); | |
7622 } | |
7623 | |
7624 return Just(true); | |
7625 } | |
7512 | 7626 |
7513 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, | 7627 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, |
7514 ShouldThrow should_throw) { | 7628 ShouldThrow should_throw) { |
7515 if (object->IsJSProxy()) { | 7629 if (object->IsJSProxy()) { |
7516 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), | 7630 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), |
7517 should_throw); | 7631 should_throw); |
7518 } | 7632 } |
7519 DCHECK(object->IsJSObject()); | 7633 DCHECK(object->IsJSObject()); |
7520 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), | 7634 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), |
7521 should_throw); | 7635 should_throw); |
(...skipping 12651 matching lines...) Loading... | |
20173 // not | 20287 // not |
20174 // depend on this. | 20288 // depend on this. |
20175 return DICTIONARY_ELEMENTS; | 20289 return DICTIONARY_ELEMENTS; |
20176 } | 20290 } |
20177 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20291 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20178 return kind; | 20292 return kind; |
20179 } | 20293 } |
20180 } | 20294 } |
20181 } // namespace internal | 20295 } // namespace internal |
20182 } // namespace v8 | 20296 } // namespace v8 |
OLD | NEW |