Commit 75a2c49c authored by rossberg@chromium.org's avatar rossberg@chromium.org

Implement delete trap for proxies.

R=ager@chromium.org
BUG=1543
TEST=

Review URL: http://codereview.chromium.org/7369001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8660 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5f1a8dc7
...@@ -189,7 +189,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver, ...@@ -189,7 +189,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
AccessorInfo* data = AccessorInfo::cast(structure); AccessorInfo* data = AccessorInfo::cast(structure);
Object* fun_obj = data->getter(); Object* fun_obj = data->getter();
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
HandleScope scope; HandleScope scope(isolate);
JSObject* self = JSObject::cast(receiver); JSObject* self = JSObject::cast(receiver);
JSObject* holder_handle = JSObject::cast(holder); JSObject* holder_handle = JSObject::cast(holder);
Handle<String> key(name); Handle<String> key(name);
...@@ -229,7 +229,7 @@ MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, ...@@ -229,7 +229,7 @@ MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
String* name_raw, String* name_raw,
Object* handler_raw) { Object* handler_raw) {
Isolate* isolate = name_raw->GetIsolate(); Isolate* isolate = name_raw->GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<Object> receiver(receiver_raw); Handle<Object> receiver(receiver_raw);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> handler(handler_raw); Handle<Object> handler(handler_raw);
...@@ -2173,9 +2173,9 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( ...@@ -2173,9 +2173,9 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
} }
} }
HandleScope scope;
Handle<Object> value_handle(value);
Heap* heap = GetHeap(); Heap* heap = GetHeap();
HandleScope scope(heap->isolate());
Handle<Object> value_handle(value);
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle; return *value_handle;
} }
...@@ -2202,7 +2202,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( ...@@ -2202,7 +2202,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode) { StrictModeFlag strict_mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<Object> receiver(this); Handle<Object> receiver(this);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> value(value_raw); Handle<Object> value(value_raw);
...@@ -2228,12 +2228,50 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( ...@@ -2228,12 +2228,50 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
} }
MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
String* name_raw, DeleteMode mode) {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> handler(this->handler());
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
return Failure::Exception();
}
// Call trap function.
Object** args[] = { name.location() };
bool has_exception;
Handle<Object> result =
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception();
Object* bool_result = result->ToBoolean();
if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
return Failure::Exception();
}
return bool_result;
}
MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
JSReceiver* receiver_raw, JSReceiver* receiver_raw,
String* name_raw, String* name_raw,
bool* has_exception) { bool* has_exception) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<JSReceiver> receiver(receiver_raw); Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> handler(this->handler()); Handle<Object> handler(this->handler());
...@@ -2322,7 +2360,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, ...@@ -2322,7 +2360,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
} }
if (result->IsReadOnly() && result->IsProperty()) { if (result->IsReadOnly() && result->IsProperty()) {
if (strict_mode == kStrictMode) { if (strict_mode == kStrictMode) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<String> key(name); Handle<String> key(name);
Handle<Object> holder(this); Handle<Object> holder(this);
Handle<Object> args[2] = { key, holder }; Handle<Object> args[2] = { key, holder };
...@@ -3176,6 +3214,15 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { ...@@ -3176,6 +3214,15 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
} }
MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
if (IsJSProxy()) {
return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
} else {
return JSObject::cast(this)->DeleteProperty(name, mode);
}
}
MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
// ECMA-262, 3rd, 8.6.2.5 // ECMA-262, 3rd, 8.6.2.5
...@@ -7527,7 +7574,7 @@ void JSArray::Expand(int required_size) { ...@@ -7527,7 +7574,7 @@ void JSArray::Expand(int required_size) {
static Failure* ArrayLengthRangeError(Heap* heap) { static Failure* ArrayLengthRangeError(Heap* heap) {
HandleScope scope; HandleScope scope(heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewRangeError("invalid_array_length", *FACTORY->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0))); HandleVector<Object>(NULL, 0)));
...@@ -7725,7 +7772,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, ...@@ -7725,7 +7772,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
// or [[Extensible]] must not violate the invariants defined in the preceding // or [[Extensible]] must not violate the invariants defined in the preceding
// paragraph. // paragraph.
if (!this->map()->is_extensible()) { if (!this->map()->is_extensible()) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<Object> handle(this, heap->isolate()); Handle<Object> handle(this, heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewTypeError("non_extensible_proto", *FACTORY->NewTypeError("non_extensible_proto",
...@@ -7739,7 +7786,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, ...@@ -7739,7 +7786,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
if (JSObject::cast(pt) == this) { if (JSObject::cast(pt) == this) {
// Cycle detected. // Cycle detected.
HandleScope scope; HandleScope scope(heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
} }
...@@ -8523,7 +8570,7 @@ MaybeObject* JSObject::SetElement(uint32_t index, ...@@ -8523,7 +8570,7 @@ MaybeObject* JSObject::SetElement(uint32_t index,
if (IsAccessCheckNeeded()) { if (IsAccessCheckNeeded()) {
Heap* heap = GetHeap(); Heap* heap = GetHeap();
if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<Object> value_handle(value); Handle<Object> value_handle(value);
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle; return *value_handle;
...@@ -11069,11 +11116,11 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { ...@@ -11069,11 +11116,11 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
template<typename Shape, typename Key> template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry, Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSObject::DeleteMode mode) { JSReceiver::DeleteMode mode) {
Heap* heap = Dictionary<Shape, Key>::GetHeap(); Heap* heap = Dictionary<Shape, Key>::GetHeap();
PropertyDetails details = DetailsAt(entry); PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion. // Ignore attributes if forcing a deletion.
if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
return heap->false_value(); return heap->false_value();
} }
SetEntry(entry, heap->null_value(), heap->null_value()); SetEntry(entry, heap->null_value(), heap->null_value());
......
...@@ -1359,6 +1359,12 @@ class HeapNumber: public HeapObject { ...@@ -1359,6 +1359,12 @@ class HeapNumber: public HeapObject {
// JSObject and JSProxy. // JSObject and JSProxy.
class JSReceiver: public HeapObject { class JSReceiver: public HeapObject {
public: public:
enum DeleteMode {
NORMAL_DELETION,
STRICT_DELETION,
FORCE_DELETION
};
// Casting. // Casting.
static inline JSReceiver* cast(Object* obj); static inline JSReceiver* cast(Object* obj);
...@@ -1373,6 +1379,8 @@ class JSReceiver: public HeapObject { ...@@ -1373,6 +1379,8 @@ class JSReceiver: public HeapObject {
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode); StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
// Returns the class name ([[Class]] property in the specification). // Returns the class name ([[Class]] property in the specification).
String* class_name(); String* class_name();
...@@ -1422,12 +1430,6 @@ class JSReceiver: public HeapObject { ...@@ -1422,12 +1430,6 @@ class JSReceiver: public HeapObject {
// caching. // caching.
class JSObject: public JSReceiver { class JSObject: public JSReceiver {
public: public:
enum DeleteMode {
NORMAL_DELETION,
STRICT_DELETION,
FORCE_DELETION
};
enum ElementsKind { enum ElementsKind {
// The "fast" kind for tagged values. Must be first to make it possible // The "fast" kind for tagged values. Must be first to make it possible
// to efficiently check maps if they have fast elements. // to efficiently check maps if they have fast elements.
...@@ -6477,14 +6479,18 @@ class JSProxy: public JSReceiver { ...@@ -6477,14 +6479,18 @@ class JSProxy: public JSReceiver {
static inline JSProxy* cast(Object* obj); static inline JSProxy* cast(Object* obj);
MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
String* name_raw, String* name,
Object* value_raw, Object* value,
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode); StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler(
String* name,
DeleteMode mode);
MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler( MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler(
JSReceiver* receiver, JSReceiver* receiver,
String* name_raw, String* name,
bool* has_exception); bool* has_exception);
// Dispatched behavior. // Dispatched behavior.
......
...@@ -3872,7 +3872,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { ...@@ -3872,7 +3872,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
|| result.type() == CONSTANT_FUNCTION)) { || result.type() == CONSTANT_FUNCTION)) {
Object* ok; Object* ok;
{ MaybeObject* maybe_ok = { MaybeObject* maybe_ok =
obj->DeleteProperty(name, JSObject::NORMAL_DELETION); obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
if (!maybe_ok->ToObject(&ok)) return maybe_ok; if (!maybe_ok->ToObject(&ok)) return maybe_ok;
} }
} }
...@@ -4126,24 +4126,25 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, ...@@ -4126,24 +4126,25 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
Handle<JSObject> js_object, Handle<JSReceiver> receiver,
Handle<Object> key) { Handle<Object> key) {
HandleScope scope(isolate); HandleScope scope(isolate);
// Check if the given key is an array index. // Check if the given key is an array index.
uint32_t index; uint32_t index;
if (key->ToArrayIndex(&index)) { if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
// In Firefox/SpiderMonkey, Safari and Opera you can access the // In Firefox/SpiderMonkey, Safari and Opera you can access the
// characters of a string using [] notation. In the case of a // characters of a string using [] notation. In the case of a
// String object we just need to redirect the deletion to the // String object we just need to redirect the deletion to the
// underlying string if the index is in range. Since the // underlying string if the index is in range. Since the
// underlying string does nothing with the deletion, we can ignore // underlying string does nothing with the deletion, we can ignore
// such deletions. // such deletions.
if (js_object->IsStringObjectWithCharacterAt(index)) { if (receiver->IsStringObjectWithCharacterAt(index)) {
return isolate->heap()->true_value(); return isolate->heap()->true_value();
} }
return js_object->DeleteElement(index, JSObject::FORCE_DELETION); return JSObject::cast(*receiver)->DeleteElement(
index, JSReceiver::FORCE_DELETION);
} }
Handle<String> key_string; Handle<String> key_string;
...@@ -4158,7 +4159,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, ...@@ -4158,7 +4159,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
} }
key_string->TryFlatten(); key_string->TryFlatten();
return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
} }
...@@ -4237,12 +4238,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { ...@@ -4237,12 +4238,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
CONVERT_CHECKED(JSObject, object, args[0]); CONVERT_CHECKED(JSReceiver, object, args[0]);
CONVERT_CHECKED(String, key, args[1]); CONVERT_CHECKED(String, key, args[1]);
CONVERT_SMI_ARG_CHECKED(strict, 2); CONVERT_SMI_ARG_CHECKED(strict, 2);
return object->DeleteProperty(key, (strict == kStrictMode) return object->DeleteProperty(key, (strict == kStrictMode)
? JSObject::STRICT_DELETION ? JSReceiver::STRICT_DELETION
: JSObject::NORMAL_DELETION); : JSReceiver::NORMAL_DELETION);
} }
...@@ -8198,9 +8199,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { ...@@ -8198,9 +8199,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
// index is non-negative. // index is non-negative.
Handle<JSObject> object = Handle<JSObject>::cast(holder); Handle<JSObject> object = Handle<JSObject>::cast(holder);
if (index >= 0) { if (index >= 0) {
return object->DeleteElement(index, JSObject::NORMAL_DELETION); return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
} else { } else {
return object->DeleteProperty(*name, JSObject::NORMAL_DELETION); return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
} }
} }
......
...@@ -636,7 +636,7 @@ class Runtime : public AllStatic { ...@@ -636,7 +636,7 @@ class Runtime : public AllStatic {
MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty( MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
Isolate* isolate, Isolate* isolate,
Handle<JSObject> object, Handle<JSReceiver> object,
Handle<Object> key); Handle<Object> key);
MUST_USE_RESULT static MaybeObject* GetObjectProperty( MUST_USE_RESULT static MaybeObject* GetObjectProperty(
......
...@@ -289,6 +289,50 @@ TestDefine(Proxy.create({ ...@@ -289,6 +289,50 @@ TestDefine(Proxy.create({
// Property deletion (delete).
var key
function TestDelete(handler) {
var o = Proxy.create(handler)
assertEquals(true, delete o.a)
assertEquals("a", key)
assertEquals(true, delete o["b"])
assertEquals("b", key)
assertEquals(false, delete o.z1)
assertEquals("z1", key)
assertEquals(false, delete o["z2"])
assertEquals("z2", key);
(function() {
"use strict"
assertEquals(true, delete o.c)
assertEquals("c", key)
assertEquals(true, delete o["d"])
assertEquals("d", key)
assertThrows(function() { delete o.z3 }, TypeError)
assertEquals("z3", key)
assertThrows(function() { delete o["z4"] }, TypeError)
assertEquals("z4", key)
})()
}
TestDelete({
'delete': function(k) { key = k; return k < "z" }
})
TestDelete({
'delete': function(k) { return this.delete2(k) },
delete2: function(k) { key = k; return k < "z" }
})
TestDelete(Proxy.create({
get: function(pr, pk) {
return function(k) { key = k; return k < "z" }
}
}))
// Property descriptors (Object.getOwnPropertyDescriptor). // Property descriptors (Object.getOwnPropertyDescriptor).
function TestDescriptor(handler) { function TestDescriptor(handler) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment