Remove ForceDelete
This method circumvented JS semantics, and should not be used. BUG= Review URL: https://codereview.chromium.org/854493004 Cr-Commit-Position: refs/heads/master@{#26157}
This commit is contained in:
parent
3eb589976a
commit
e99faf93ff
@ -2432,10 +2432,6 @@ class V8_EXPORT Object : public Value {
|
||||
|
||||
bool Delete(Handle<Value> key);
|
||||
|
||||
// Delete a property on this object bypassing interceptors and
|
||||
// ignoring dont-delete attributes.
|
||||
bool ForceDelete(Handle<Value> key);
|
||||
|
||||
bool Has(uint32_t index);
|
||||
|
||||
bool Delete(uint32_t index);
|
||||
|
27
src/api.cc
27
src/api.cc
@ -3011,7 +3011,7 @@ bool v8::Object::SetPrivate(v8::Handle<Private> key, v8::Handle<Value> value) {
|
||||
|
||||
i::MaybeHandle<i::Object> DeleteObjectProperty(
|
||||
i::Isolate* isolate, i::Handle<i::JSReceiver> receiver,
|
||||
i::Handle<i::Object> key, i::JSReceiver::DeleteMode mode) {
|
||||
i::Handle<i::Object> key, i::StrictMode strict_mode) {
|
||||
// Check if the given key is an array index.
|
||||
uint32_t index;
|
||||
if (key->ToArrayIndex(&index)) {
|
||||
@ -3025,7 +3025,7 @@ i::MaybeHandle<i::Object> DeleteObjectProperty(
|
||||
return isolate->factory()->true_value();
|
||||
}
|
||||
|
||||
return i::JSReceiver::DeleteElement(receiver, index, mode);
|
||||
return i::JSReceiver::DeleteElement(receiver, index, strict_mode);
|
||||
}
|
||||
|
||||
i::Handle<i::Name> name;
|
||||
@ -3043,25 +3043,7 @@ i::MaybeHandle<i::Object> DeleteObjectProperty(
|
||||
if (name->IsString()) {
|
||||
name = i::String::Flatten(i::Handle<i::String>::cast(name));
|
||||
}
|
||||
return i::JSReceiver::DeleteProperty(receiver, name, mode);
|
||||
}
|
||||
|
||||
|
||||
bool v8::Object::ForceDelete(v8::Handle<Value> key) {
|
||||
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
|
||||
ON_BAILOUT(isolate, "v8::Object::ForceDelete()", return false);
|
||||
ENTER_V8(isolate);
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
|
||||
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
|
||||
|
||||
EXCEPTION_PREAMBLE(isolate);
|
||||
i::Handle<i::Object> obj;
|
||||
has_pending_exception =
|
||||
!DeleteObjectProperty(isolate, self, key_obj,
|
||||
i::JSReceiver::FORCE_DELETION).ToHandle(&obj);
|
||||
EXCEPTION_BAILOUT_CHECK(isolate, false);
|
||||
return obj->IsTrue();
|
||||
return i::JSReceiver::DeleteProperty(receiver, name, strict_mode);
|
||||
}
|
||||
|
||||
|
||||
@ -3365,8 +3347,7 @@ bool v8::Object::Delete(v8::Handle<Value> key) {
|
||||
EXCEPTION_PREAMBLE(isolate);
|
||||
i::Handle<i::Object> obj;
|
||||
has_pending_exception =
|
||||
!DeleteObjectProperty(isolate, self, key_obj,
|
||||
i::JSReceiver::NORMAL_DELETION).ToHandle(&obj);
|
||||
!DeleteObjectProperty(isolate, self, key_obj, i::SLOPPY).ToHandle(&obj);
|
||||
EXCEPTION_BAILOUT_CHECK(isolate, false);
|
||||
return obj->IsTrue();
|
||||
}
|
||||
|
@ -691,9 +691,7 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
}
|
||||
|
||||
MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
|
||||
Handle<JSObject> obj,
|
||||
uint32_t key,
|
||||
JSReceiver::DeleteMode mode) OVERRIDE = 0;
|
||||
Handle<JSObject> obj, uint32_t key, StrictMode strict_mode) OVERRIDE = 0;
|
||||
|
||||
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
|
||||
FixedArrayBase* to, ElementsKind from_kind,
|
||||
@ -915,9 +913,8 @@ class FastElementsAccessor
|
||||
return length_object;
|
||||
}
|
||||
|
||||
static Handle<Object> DeleteCommon(Handle<JSObject> obj,
|
||||
uint32_t key,
|
||||
JSReceiver::DeleteMode mode) {
|
||||
static Handle<Object> DeleteCommon(Handle<JSObject> obj, uint32_t key,
|
||||
StrictMode strict_mode) {
|
||||
DCHECK(obj->HasFastSmiOrObjectElements() ||
|
||||
obj->HasFastDoubleElements() ||
|
||||
obj->HasFastArgumentsElements());
|
||||
@ -975,8 +972,8 @@ class FastElementsAccessor
|
||||
}
|
||||
|
||||
virtual MaybeHandle<Object> Delete(Handle<JSObject> obj, uint32_t key,
|
||||
JSReceiver::DeleteMode mode) FINAL {
|
||||
return DeleteCommon(obj, key, mode);
|
||||
StrictMode strict_mode) FINAL {
|
||||
return DeleteCommon(obj, key, strict_mode);
|
||||
}
|
||||
|
||||
static bool HasElementImpl(
|
||||
@ -1298,7 +1295,7 @@ class TypedElementsAccessor
|
||||
}
|
||||
|
||||
MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
|
||||
Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
|
||||
Handle<JSObject> obj, uint32_t key, StrictMode strict_mode) FINAL {
|
||||
// External arrays always ignore deletes.
|
||||
return obj->GetIsolate()->factory()->true_value();
|
||||
}
|
||||
@ -1397,9 +1394,7 @@ class DictionaryElementsAccessor
|
||||
}
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteCommon(
|
||||
Handle<JSObject> obj,
|
||||
uint32_t key,
|
||||
JSReceiver::DeleteMode mode) {
|
||||
Handle<JSObject> obj, uint32_t key, StrictMode strict_mode) {
|
||||
Isolate* isolate = obj->GetIsolate();
|
||||
Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()),
|
||||
isolate);
|
||||
@ -1413,9 +1408,9 @@ class DictionaryElementsAccessor
|
||||
int entry = dictionary->FindEntry(key);
|
||||
if (entry != SeededNumberDictionary::kNotFound) {
|
||||
Handle<Object> result =
|
||||
SeededNumberDictionary::DeleteProperty(dictionary, entry, mode);
|
||||
SeededNumberDictionary::DeleteProperty(dictionary, entry);
|
||||
if (*result == *isolate->factory()->false_value()) {
|
||||
if (mode == JSObject::STRICT_DELETION) {
|
||||
if (strict_mode == STRICT) {
|
||||
// Deleting a non-configurable property in strict mode.
|
||||
Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
|
||||
Handle<Object> args[2] = { name, obj };
|
||||
@ -1450,8 +1445,8 @@ class DictionaryElementsAccessor
|
||||
ElementsKindTraits<DICTIONARY_ELEMENTS> >;
|
||||
|
||||
MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
|
||||
Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
|
||||
return DeleteCommon(obj, key, mode);
|
||||
Handle<JSObject> obj, uint32_t key, StrictMode strict_mode) FINAL {
|
||||
return DeleteCommon(obj, key, strict_mode);
|
||||
}
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
|
||||
@ -1622,7 +1617,7 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
|
||||
}
|
||||
|
||||
MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
|
||||
Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
|
||||
Handle<JSObject> obj, uint32_t key, StrictMode strict_mode) FINAL {
|
||||
Isolate* isolate = obj->GetIsolate();
|
||||
Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
|
||||
Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
|
||||
@ -1634,12 +1629,13 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
|
||||
} else {
|
||||
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
|
||||
if (arguments->IsDictionary()) {
|
||||
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
|
||||
return DictionaryElementsAccessor::DeleteCommon(obj, key, strict_mode);
|
||||
} else {
|
||||
// It's difficult to access the version of DeleteCommon that is declared
|
||||
// in the templatized super class, call the concrete implementation in
|
||||
// the class for the most generalized ElementsKind subclass.
|
||||
return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
|
||||
return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key,
|
||||
strict_mode);
|
||||
}
|
||||
}
|
||||
return isolate->factory()->true_value();
|
||||
|
@ -121,9 +121,7 @@ class ElementsAccessor {
|
||||
|
||||
// Deletes an element in an object, returning a new elements backing store.
|
||||
MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
|
||||
Handle<JSObject> holder,
|
||||
uint32_t key,
|
||||
JSReceiver::DeleteMode mode) = 0;
|
||||
Handle<JSObject> holder, uint32_t key, StrictMode strict_mode) = 0;
|
||||
|
||||
// If kCopyToEnd is specified as the copy_size to CopyElements, it copies all
|
||||
// of elements from source after source_start to the destination array.
|
||||
|
162
src/objects.cc
162
src/objects.cc
@ -530,56 +530,6 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode) {
|
||||
DCHECK(!object->HasFastProperties());
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
int entry = dictionary->FindEntry(name);
|
||||
if (entry != NameDictionary::kNotFound) {
|
||||
// If we have a global object set the cell to the hole.
|
||||
if (object->IsGlobalObject()) {
|
||||
PropertyDetails details = dictionary->DetailsAt(entry);
|
||||
if (!details.IsConfigurable()) {
|
||||
if (mode != FORCE_DELETION) return isolate->factory()->false_value();
|
||||
// When forced to delete global properties, we have to make a
|
||||
// map change to invalidate any ICs that think they can load
|
||||
// from the non-configurable cell without checking if it contains
|
||||
// the hole value.
|
||||
Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
|
||||
DCHECK(new_map->is_dictionary_map());
|
||||
#if TRACE_MAPS
|
||||
if (FLAG_trace_maps) {
|
||||
PrintF("[TraceMaps: GlobalDeleteNormalized from= %p to= %p ]\n",
|
||||
reinterpret_cast<void*>(object->map()),
|
||||
reinterpret_cast<void*>(*new_map));
|
||||
}
|
||||
#endif
|
||||
JSObject::MigrateToMap(object, new_map);
|
||||
// Optimized code does not check for the hole value for non-configurable
|
||||
// properties.
|
||||
Deoptimizer::DeoptimizeGlobalObject(*object);
|
||||
}
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
Handle<Object> value = isolate->factory()->the_hole_value();
|
||||
PropertyCell::SetValueInferType(cell, value);
|
||||
dictionary->DetailsAtPut(entry, details.AsDeleted());
|
||||
} else {
|
||||
Handle<Object> deleted(
|
||||
NameDictionary::DeleteProperty(dictionary, entry, mode));
|
||||
if (*deleted == isolate->heap()->true_value()) {
|
||||
Handle<NameDictionary> new_properties =
|
||||
NameDictionary::Shrink(dictionary, name);
|
||||
object->set_properties(*new_properties);
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
return isolate->factory()->true_value();
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
|
||||
Handle<Object> object,
|
||||
Handle<Object> receiver,
|
||||
@ -3551,8 +3501,9 @@ MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
|
||||
Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
|
||||
MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(Handle<JSProxy> proxy,
|
||||
Handle<Name> name,
|
||||
StrictMode strict_mode) {
|
||||
Isolate* isolate = proxy->GetIsolate();
|
||||
|
||||
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
|
||||
@ -3570,7 +3521,7 @@ MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
|
||||
Object);
|
||||
|
||||
bool result_bool = result->BooleanValue();
|
||||
if (mode == STRICT_DELETION && !result_bool) {
|
||||
if (strict_mode == STRICT && !result_bool) {
|
||||
Handle<Object> handler(proxy->handler(), isolate);
|
||||
Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
|
||||
STATIC_CHAR_VECTOR("delete"));
|
||||
@ -3583,11 +3534,12 @@ MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
|
||||
Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
|
||||
MaybeHandle<Object> JSProxy::DeleteElementWithHandler(Handle<JSProxy> proxy,
|
||||
uint32_t index,
|
||||
StrictMode strict_mode) {
|
||||
Isolate* isolate = proxy->GetIsolate();
|
||||
Handle<String> name = isolate->factory()->Uint32ToString(index);
|
||||
return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
|
||||
return JSProxy::DeletePropertyWithHandler(proxy, name, strict_mode);
|
||||
}
|
||||
|
||||
|
||||
@ -4867,15 +4819,16 @@ MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
|
||||
// Rebox CustomArguments::kReturnValueOffset before returning.
|
||||
return handle(*result_internal, isolate);
|
||||
}
|
||||
MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
|
||||
object, index, NORMAL_DELETION);
|
||||
// TODO(verwaest): Shouldn't this be the mode that was passed in?
|
||||
MaybeHandle<Object> delete_result =
|
||||
object->GetElementsAccessor()->Delete(object, index, SLOPPY);
|
||||
return delete_result;
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
DeleteMode mode) {
|
||||
StrictMode strict_mode) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
@ -4888,7 +4841,7 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
if (object->IsStringObjectWithCharacterAt(index)) {
|
||||
if (mode == STRICT_DELETION) {
|
||||
if (strict_mode == STRICT) {
|
||||
// Deleting a non-configurable property in strict mode.
|
||||
Handle<Object> name = factory->NewNumberFromUint(index);
|
||||
Handle<Object> args[2] = { name, object };
|
||||
@ -4905,7 +4858,7 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
||||
DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
|
||||
return DeleteElement(
|
||||
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
|
||||
mode);
|
||||
strict_mode);
|
||||
}
|
||||
|
||||
Handle<Object> old_value;
|
||||
@ -4926,10 +4879,11 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
||||
|
||||
// Skip interceptor if forcing deletion.
|
||||
MaybeHandle<Object> maybe_result;
|
||||
if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
|
||||
if (object->HasIndexedInterceptor()) {
|
||||
maybe_result = DeleteElementWithInterceptor(object, index);
|
||||
} else {
|
||||
maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
|
||||
maybe_result =
|
||||
object->GetElementsAccessor()->Delete(object, index, strict_mode);
|
||||
}
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
|
||||
@ -4949,23 +4903,44 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
void JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<Name> name) {
|
||||
DCHECK(!object->HasFastProperties());
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
int entry = dictionary->FindEntry(name);
|
||||
DCHECK_NE(NameDictionary::kNotFound, entry);
|
||||
|
||||
// If we have a global object set the cell to the hole.
|
||||
if (object->IsGlobalObject()) {
|
||||
PropertyDetails details = dictionary->DetailsAt(entry);
|
||||
DCHECK(details.IsConfigurable());
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
Handle<Object> value = isolate->factory()->the_hole_value();
|
||||
PropertyCell::SetValueInferType(cell, value);
|
||||
dictionary->DetailsAtPut(entry, details.AsDeleted());
|
||||
return;
|
||||
}
|
||||
|
||||
NameDictionary::DeleteProperty(dictionary, entry);
|
||||
Handle<NameDictionary> new_properties =
|
||||
NameDictionary::Shrink(dictionary, name);
|
||||
object->set_properties(*new_properties);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode delete_mode) {
|
||||
StrictMode strict_mode) {
|
||||
// ECMA-262, 3rd, 8.6.2.5
|
||||
DCHECK(name->IsName());
|
||||
|
||||
uint32_t index = 0;
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
return DeleteElement(object, index, delete_mode);
|
||||
return DeleteElement(object, index, strict_mode);
|
||||
}
|
||||
|
||||
// Skip interceptors on FORCE_DELETION.
|
||||
LookupIterator::Configuration config =
|
||||
delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR
|
||||
: LookupIterator::HIDDEN;
|
||||
|
||||
LookupIterator it(object, name, config);
|
||||
LookupIterator it(object, name, LookupIterator::HIDDEN);
|
||||
|
||||
bool is_observed = object->map()->is_observed() &&
|
||||
!it.isolate()->IsInternallyUsedPropertyName(name);
|
||||
@ -4999,9 +4974,9 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
}
|
||||
// Fall through.
|
||||
case LookupIterator::ACCESSOR: {
|
||||
if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
|
||||
if (!it.IsConfigurable()) {
|
||||
// Fail if the property is not configurable.
|
||||
if (delete_mode == STRICT_DELETION) {
|
||||
if (strict_mode == STRICT) {
|
||||
Handle<Object> args[2] = {name, object};
|
||||
THROW_NEW_ERROR(it.isolate(),
|
||||
NewTypeError("strict_delete_property",
|
||||
@ -5021,9 +4996,9 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
!(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
|
||||
return it.isolate()->factory()->true_value();
|
||||
}
|
||||
|
||||
NormalizeProperties(holder, mode, 0, "DeletingProperty");
|
||||
Handle<Object> result =
|
||||
DeleteNormalizedProperty(holder, name, delete_mode);
|
||||
DeleteNormalizedProperty(holder, name);
|
||||
ReoptimizeIfPrototype(holder);
|
||||
|
||||
if (is_observed) {
|
||||
@ -5032,7 +5007,7 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
EnqueueChangeRecord(object, "delete", name, old_value), Object);
|
||||
}
|
||||
|
||||
return result;
|
||||
return it.isolate()->factory()->true_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5043,23 +5018,25 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
|
||||
MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
|
||||
uint32_t index,
|
||||
DeleteMode mode) {
|
||||
StrictMode strict_mode) {
|
||||
if (object->IsJSProxy()) {
|
||||
return JSProxy::DeleteElementWithHandler(
|
||||
Handle<JSProxy>::cast(object), index, mode);
|
||||
return JSProxy::DeleteElementWithHandler(Handle<JSProxy>::cast(object),
|
||||
index, strict_mode);
|
||||
}
|
||||
return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
|
||||
return JSObject::DeleteElement(Handle<JSObject>::cast(object), index,
|
||||
strict_mode);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode) {
|
||||
StrictMode strict_mode) {
|
||||
if (object->IsJSProxy()) {
|
||||
return JSProxy::DeletePropertyWithHandler(
|
||||
Handle<JSProxy>::cast(object), name, mode);
|
||||
return JSProxy::DeletePropertyWithHandler(Handle<JSProxy>::cast(object),
|
||||
name, strict_mode);
|
||||
}
|
||||
return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
|
||||
return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name,
|
||||
strict_mode);
|
||||
}
|
||||
|
||||
|
||||
@ -14473,11 +14450,11 @@ Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
|
||||
|
||||
template Handle<Object>
|
||||
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
|
||||
Handle<NameDictionary>, int, JSObject::DeleteMode);
|
||||
Handle<NameDictionary>, int);
|
||||
|
||||
template Handle<Object>
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
|
||||
DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
|
||||
uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
|
||||
|
||||
template Handle<NameDictionary>
|
||||
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
|
||||
@ -15455,17 +15432,12 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
|
||||
}
|
||||
|
||||
|
||||
template<typename Derived, typename Shape, typename Key>
|
||||
template <typename Derived, typename Shape, typename Key>
|
||||
Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
|
||||
Handle<Derived> dictionary,
|
||||
int entry,
|
||||
JSObject::DeleteMode mode) {
|
||||
Handle<Derived> dictionary, int entry) {
|
||||
Factory* factory = dictionary->GetIsolate()->factory();
|
||||
PropertyDetails details = dictionary->DetailsAt(entry);
|
||||
// Ignore attributes if forcing a deletion.
|
||||
if (!details.IsConfigurable() && mode != JSReceiver::FORCE_DELETION) {
|
||||
return factory->false_value();
|
||||
}
|
||||
if (!details.IsConfigurable()) return factory->false_value();
|
||||
|
||||
dictionary->SetEntry(
|
||||
entry, factory->the_hole_value(), factory->the_hole_value());
|
||||
|
@ -1589,12 +1589,6 @@ enum AccessorComponent {
|
||||
// JSObject and JSProxy.
|
||||
class JSReceiver: public HeapObject {
|
||||
public:
|
||||
enum DeleteMode {
|
||||
NORMAL_DELETION,
|
||||
STRICT_DELETION,
|
||||
FORCE_DELETION
|
||||
};
|
||||
|
||||
DECLARE_CAST(JSReceiver)
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetElement(
|
||||
@ -1616,13 +1610,11 @@ class JSReceiver: public HeapObject {
|
||||
|
||||
// Implementation of [[Delete]], ECMA-262 5th edition, section 8.12.7.
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteProperty(
|
||||
Handle<JSReceiver> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode = NORMAL_DELETION);
|
||||
Handle<JSReceiver> object, Handle<Name> name,
|
||||
StrictMode strict_mode = SLOPPY);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteElement(
|
||||
Handle<JSReceiver> object,
|
||||
uint32_t index,
|
||||
DeleteMode mode = NORMAL_DELETION);
|
||||
Handle<JSReceiver> object, uint32_t index,
|
||||
StrictMode strict_mode = SLOPPY);
|
||||
|
||||
// Tests for the fast common case for property enumeration.
|
||||
bool IsSimpleEnum();
|
||||
@ -2341,21 +2333,16 @@ class JSObject: public JSReceiver {
|
||||
PropertyAttributes attributes);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteProperty(
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode);
|
||||
Handle<JSObject> object, Handle<Name> name, StrictMode strict_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeletePropertyWithInterceptor(
|
||||
Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name);
|
||||
|
||||
// Deletes the named property in a normalized object.
|
||||
static Handle<Object> DeleteNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode);
|
||||
// Deletes an existing named property in a normalized object.
|
||||
static void DeleteNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<Name> name);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteElement(
|
||||
Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
DeleteMode mode);
|
||||
Handle<JSObject> object, uint32_t index, StrictMode strict_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteElementWithInterceptor(
|
||||
Handle<JSObject> object,
|
||||
uint32_t index);
|
||||
@ -3556,10 +3543,7 @@ class Dictionary: public HashTable<Derived, Shape, Key> {
|
||||
void CopyValuesTo(FixedArray* elements);
|
||||
|
||||
// Delete a property from the dictionary.
|
||||
static Handle<Object> DeleteProperty(
|
||||
Handle<Derived> dictionary,
|
||||
int entry,
|
||||
JSObject::DeleteMode mode);
|
||||
static Handle<Object> DeleteProperty(Handle<Derived> dictionary, int entry);
|
||||
|
||||
// Attempt to shrink the dictionary after deletion of key.
|
||||
MUST_USE_RESULT static inline Handle<Derived> Shrink(
|
||||
@ -9843,13 +9827,9 @@ class JSProxy: public JSReceiver {
|
||||
Handle<JSProxy> proxy, uint32_t index);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeletePropertyWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<Name> name,
|
||||
DeleteMode mode);
|
||||
Handle<JSProxy> proxy, Handle<Name> name, StrictMode strict_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> DeleteElementWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
uint32_t index,
|
||||
DeleteMode mode);
|
||||
Handle<JSProxy> proxy, uint32_t index, StrictMode strict_mode);
|
||||
|
||||
MUST_USE_RESULT Object* GetIdentityHash();
|
||||
|
||||
|
@ -765,12 +765,9 @@ RUNTIME_FUNCTION(Runtime_DeleteProperty) {
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
||||
CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
|
||||
JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
|
||||
? JSReceiver::STRICT_DELETION
|
||||
: JSReceiver::NORMAL_DELETION;
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
|
||||
isolate, result, JSReceiver::DeleteProperty(object, key, strict_mode));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
@ -16221,139 +16221,6 @@ TEST(ForceSetWithInterceptor) {
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ForceDelete) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
|
||||
LocalContext context(NULL, templ);
|
||||
v8::Handle<v8::Object> global = context->Global();
|
||||
|
||||
// Ordinary properties
|
||||
v8::Handle<v8::String> simple_property =
|
||||
v8::String::NewFromUtf8(isolate, "p");
|
||||
global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
|
||||
CHECK_EQ(4, global->Get(simple_property)->Int32Value());
|
||||
// This should fail because the property is dont-delete.
|
||||
CHECK(!global->Delete(simple_property));
|
||||
CHECK_EQ(4, global->Get(simple_property)->Int32Value());
|
||||
// This should succeed even though the property is dont-delete.
|
||||
CHECK(global->ForceDelete(simple_property));
|
||||
CHECK(global->Get(simple_property)->IsUndefined());
|
||||
}
|
||||
|
||||
|
||||
static int force_delete_interceptor_count = 0;
|
||||
static bool pass_on_delete = false;
|
||||
|
||||
|
||||
static void ForceDeleteDeleter(
|
||||
v8::Local<v8::Name> name,
|
||||
const v8::PropertyCallbackInfo<v8::Boolean>& info) {
|
||||
force_delete_interceptor_count++;
|
||||
if (pass_on_delete) return;
|
||||
info.GetReturnValue().Set(true);
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ForceDeleteWithInterceptor) {
|
||||
force_delete_interceptor_count = 0;
|
||||
pass_on_delete = false;
|
||||
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
|
||||
templ->SetHandler(
|
||||
v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
|
||||
LocalContext context(NULL, templ);
|
||||
v8::Handle<v8::Object> global = context->Global();
|
||||
|
||||
v8::Handle<v8::String> some_property =
|
||||
v8::String::NewFromUtf8(isolate, "a");
|
||||
global->ForceSet(some_property, v8::Integer::New(isolate, 42),
|
||||
v8::DontDelete);
|
||||
|
||||
// Deleting a property should get intercepted and nothing should
|
||||
// happen.
|
||||
CHECK_EQ(0, force_delete_interceptor_count);
|
||||
CHECK(global->Delete(some_property));
|
||||
CHECK_EQ(1, force_delete_interceptor_count);
|
||||
CHECK_EQ(42, global->Get(some_property)->Int32Value());
|
||||
// Deleting the property when the interceptor returns an empty
|
||||
// handle should not delete the property since it is DontDelete.
|
||||
pass_on_delete = true;
|
||||
CHECK(!global->Delete(some_property));
|
||||
CHECK_EQ(2, force_delete_interceptor_count);
|
||||
CHECK_EQ(42, global->Get(some_property)->Int32Value());
|
||||
// Forcing the property to be deleted should delete the value
|
||||
// without calling the interceptor.
|
||||
CHECK(global->ForceDelete(some_property));
|
||||
CHECK(global->Get(some_property)->IsUndefined());
|
||||
CHECK_EQ(2, force_delete_interceptor_count);
|
||||
}
|
||||
|
||||
|
||||
// Make sure that forcing a delete invalidates any IC stubs, so we
|
||||
// don't read the hole value.
|
||||
THREADED_TEST(ForceDeleteIC) {
|
||||
LocalContext context;
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
// Create a DontDelete variable on the global object.
|
||||
CompileRun("this.__proto__ = { foo: 'horse' };"
|
||||
"var foo = 'fish';"
|
||||
"function f() { return foo.length; }");
|
||||
// Initialize the IC for foo in f.
|
||||
CompileRun("for (var i = 0; i < 4; i++) f();");
|
||||
// Make sure the value of foo is correct before the deletion.
|
||||
CHECK_EQ(4, CompileRun("f()")->Int32Value());
|
||||
// Force the deletion of foo.
|
||||
CHECK(context->Global()->ForceDelete(v8_str("foo")));
|
||||
// Make sure the value for foo is read from the prototype, and that
|
||||
// we don't get in trouble with reading the deleted cell value
|
||||
// sentinel.
|
||||
CHECK_EQ(5, CompileRun("f()")->Int32Value());
|
||||
}
|
||||
|
||||
|
||||
TEST(InlinedFunctionAcrossContexts) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope outer_scope(isolate);
|
||||
v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
|
||||
v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
|
||||
ctx1->Enter();
|
||||
|
||||
{
|
||||
v8::HandleScope inner_scope(CcTest::isolate());
|
||||
CompileRun("var G = 42; function foo() { return G; }");
|
||||
v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
|
||||
ctx2->Enter();
|
||||
ctx2->Global()->Set(v8_str("o"), foo);
|
||||
v8::Local<v8::Value> res = CompileRun(
|
||||
"function f() { return o(); }"
|
||||
"for (var i = 0; i < 10; ++i) f();"
|
||||
"%OptimizeFunctionOnNextCall(f);"
|
||||
"f();");
|
||||
CHECK_EQ(42, res->Int32Value());
|
||||
ctx2->Exit();
|
||||
v8::Handle<v8::String> G_property =
|
||||
v8::String::NewFromUtf8(CcTest::isolate(), "G");
|
||||
CHECK(ctx1->Global()->ForceDelete(G_property));
|
||||
ctx2->Enter();
|
||||
ExpectString(
|
||||
"(function() {"
|
||||
" try {"
|
||||
" return f();"
|
||||
" } catch(e) {"
|
||||
" return e.toString();"
|
||||
" }"
|
||||
" })()",
|
||||
"ReferenceError: G is not defined");
|
||||
ctx2->Exit();
|
||||
ctx1->Exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static v8::Local<Context> calling_context0;
|
||||
static v8::Local<Context> calling_context1;
|
||||
static v8::Local<Context> calling_context2;
|
||||
@ -20821,62 +20688,6 @@ TEST(DontDeleteCellLoadIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(DontDeleteCellLoadICForceDelete) {
|
||||
const char* function_code =
|
||||
"function readCell() { while (true) { return cell; } }";
|
||||
|
||||
// Run the code twice to initialize the load IC for a don't delete
|
||||
// cell.
|
||||
LocalContext context;
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
CompileRun("var cell = \"value\";");
|
||||
ExpectBoolean("delete cell", false);
|
||||
CompileRun(function_code);
|
||||
ExpectString("readCell()", "value");
|
||||
ExpectString("readCell()", "value");
|
||||
|
||||
// Delete the cell using the API and check the inlined code works
|
||||
// correctly.
|
||||
CHECK(context->Global()->ForceDelete(v8_str("cell")));
|
||||
ExpectString("(function() {"
|
||||
" try {"
|
||||
" return readCell();"
|
||||
" } catch(e) {"
|
||||
" return e.toString();"
|
||||
" }"
|
||||
"})()",
|
||||
"ReferenceError: cell is not defined");
|
||||
}
|
||||
|
||||
|
||||
TEST(DontDeleteCellLoadICAPI) {
|
||||
const char* function_code =
|
||||
"function readCell() { while (true) { return cell; } }";
|
||||
|
||||
// Run the code twice to initialize the load IC for a don't delete
|
||||
// cell created using the API.
|
||||
LocalContext context;
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
|
||||
ExpectBoolean("delete cell", false);
|
||||
CompileRun(function_code);
|
||||
ExpectString("readCell()", "value");
|
||||
ExpectString("readCell()", "value");
|
||||
|
||||
// Delete the cell using the API and check the inlined code works
|
||||
// correctly.
|
||||
CHECK(context->Global()->ForceDelete(v8_str("cell")));
|
||||
ExpectString("(function() {"
|
||||
" try {"
|
||||
" return readCell();"
|
||||
" } catch(e) {"
|
||||
" return e.toString();"
|
||||
" }"
|
||||
"})()",
|
||||
"ReferenceError: cell is not defined");
|
||||
}
|
||||
|
||||
|
||||
class Visitor42 : public v8::PersistentHandleVisitor {
|
||||
public:
|
||||
explicit Visitor42(v8::Persistent<v8::Object>* object)
|
||||
|
@ -650,7 +650,7 @@ TEST(ObjectProperties) {
|
||||
CHECK(maybe.value);
|
||||
|
||||
// delete first
|
||||
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
|
||||
JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
|
||||
maybe = JSReceiver::HasOwnProperty(obj, first);
|
||||
CHECK(maybe.has_value);
|
||||
CHECK(!maybe.value);
|
||||
@ -666,11 +666,11 @@ TEST(ObjectProperties) {
|
||||
CHECK(maybe.value);
|
||||
|
||||
// delete first and then second
|
||||
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
|
||||
JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
|
||||
maybe = JSReceiver::HasOwnProperty(obj, second);
|
||||
CHECK(maybe.has_value);
|
||||
CHECK(maybe.value);
|
||||
JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
|
||||
JSReceiver::DeleteProperty(obj, second, SLOPPY).Check();
|
||||
maybe = JSReceiver::HasOwnProperty(obj, first);
|
||||
CHECK(maybe.has_value);
|
||||
CHECK(!maybe.value);
|
||||
@ -689,11 +689,11 @@ TEST(ObjectProperties) {
|
||||
CHECK(maybe.value);
|
||||
|
||||
// delete second and then first
|
||||
JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
|
||||
JSReceiver::DeleteProperty(obj, second, SLOPPY).Check();
|
||||
maybe = JSReceiver::HasOwnProperty(obj, first);
|
||||
CHECK(maybe.has_value);
|
||||
CHECK(maybe.value);
|
||||
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
|
||||
JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
|
||||
maybe = JSReceiver::HasOwnProperty(obj, first);
|
||||
CHECK(maybe.has_value);
|
||||
CHECK(!maybe.value);
|
||||
|
@ -328,11 +328,10 @@ TEST(APITestBasicMutation) {
|
||||
// Setting an indexed element via the property setting method
|
||||
obj->Set(Number::New(v8_isolate, 1), Number::New(v8_isolate, 5));
|
||||
// Setting with a non-String, non-uint32 key
|
||||
obj->ForceSet(Number::New(v8_isolate, 1.1), Number::New(v8_isolate, 6),
|
||||
DontDelete);
|
||||
obj->Set(Number::New(v8_isolate, 1.1), Number::New(v8_isolate, 6));
|
||||
obj->Delete(String::NewFromUtf8(v8_isolate, "foo"));
|
||||
obj->Delete(1);
|
||||
obj->ForceDelete(Number::New(v8_isolate, 1.1));
|
||||
obj->Delete(Number::New(v8_isolate, 1.1));
|
||||
|
||||
// Force delivery
|
||||
// TODO(adamk): Should the above set methods trigger delivery themselves?
|
||||
|
Loading…
Reference in New Issue
Block a user