Commit 24d22b56 authored by ager@chromium.org's avatar ager@chromium.org

Introduce an API to force the deletion of a property ignoring

interceptors and dont-delete attributes.

Minor change to the behavior of eval: throw exception when calling
eval in a context for which the global has been detached.  This
matches the behavior of both Firefox and Safari post navigation in the
browser.
Review URL: http://codereview.chromium.org/118374

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2118 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f04220d2
...@@ -1056,7 +1056,7 @@ class V8EXPORT Object : public Value { ...@@ -1056,7 +1056,7 @@ class V8EXPORT Object : public Value {
Handle<Value> value, Handle<Value> value,
PropertyAttribute attribs = None); PropertyAttribute attribs = None);
// Sets a local property on this object, bypassing interceptors and // Sets a local property on this object bypassing interceptors and
// overriding accessors or read-only properties. // overriding accessors or read-only properties.
// //
// Note that if the object has an interceptor the property will be set // Note that if the object has an interceptor the property will be set
...@@ -1067,13 +1067,21 @@ class V8EXPORT Object : public Value { ...@@ -1067,13 +1067,21 @@ class V8EXPORT Object : public Value {
bool ForceSet(Handle<Value> key, bool ForceSet(Handle<Value> key,
Handle<Value> value, Handle<Value> value,
PropertyAttribute attribs = None); PropertyAttribute attribs = None);
Local<Value> Get(Handle<Value> key); Local<Value> Get(Handle<Value> key);
// TODO(1245389): Replace the type-specific versions of these // TODO(1245389): Replace the type-specific versions of these
// functions with generic ones that accept a Handle<Value> key. // functions with generic ones that accept a Handle<Value> key.
bool Has(Handle<String> key); bool Has(Handle<String> key);
bool Delete(Handle<String> key); bool Delete(Handle<String> 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 Has(uint32_t index);
bool Delete(uint32_t index); bool Delete(uint32_t index);
/** /**
......
...@@ -1892,6 +1892,19 @@ bool v8::Object::ForceSet(v8::Handle<Value> key, ...@@ -1892,6 +1892,19 @@ bool v8::Object::ForceSet(v8::Handle<Value> key,
} }
bool v8::Object::ForceDelete(v8::Handle<Value> key) {
ON_BAILOUT("v8::Object::ForceDelete()", return false);
ENTER_V8;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
EXCEPTION_PREAMBLE();
i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj);
has_pending_exception = obj.is_null();
EXCEPTION_BAILOUT_CHECK(false);
return obj->IsTrue();
}
Local<Value> v8::Object::Get(v8::Handle<Value> key) { Local<Value> v8::Object::Get(v8::Handle<Value> key) {
ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>()); ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
ENTER_V8; ENTER_V8;
......
...@@ -222,6 +222,12 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object, ...@@ -222,6 +222,12 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
} }
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key) {
CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
}
Handle<Object> IgnoreAttributesAndSetLocalProperty( Handle<Object> IgnoreAttributesAndSetLocalProperty(
Handle<JSObject> object, Handle<JSObject> object,
Handle<String> key, Handle<String> key,
...@@ -231,6 +237,7 @@ Handle<Object> IgnoreAttributesAndSetLocalProperty( ...@@ -231,6 +237,7 @@ Handle<Object> IgnoreAttributesAndSetLocalProperty(
IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object); IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
} }
Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object, Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
Handle<String> key, Handle<String> key,
Handle<Object> value, Handle<Object> value,
...@@ -308,13 +315,15 @@ Handle<Object> GetHiddenProperties(Handle<JSObject> obj, ...@@ -308,13 +315,15 @@ Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
Handle<Object> DeleteElement(Handle<JSObject> obj, Handle<Object> DeleteElement(Handle<JSObject> obj,
uint32_t index) { uint32_t index) {
CALL_HEAP_FUNCTION(obj->DeleteElement(index), Object); CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION),
Object);
} }
Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<Object> DeleteProperty(Handle<JSObject> obj,
Handle<String> prop) { Handle<String> prop) {
CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop), Object); CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
Object);
} }
......
...@@ -202,6 +202,9 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object, ...@@ -202,6 +202,9 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key);
Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object, Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
Handle<String> key, Handle<String> key,
Handle<Object> value, Handle<Object> value,
......
...@@ -385,7 +385,9 @@ Object* JSObject::SetLazyProperty(LookupResult* result, ...@@ -385,7 +385,9 @@ Object* JSObject::SetLazyProperty(LookupResult* result,
} }
Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) { Object* JSObject::DeleteLazyProperty(LookupResult* result,
String* name,
DeleteMode mode) {
HandleScope scope; HandleScope scope;
Handle<JSObject> this_handle(this); Handle<JSObject> this_handle(this);
Handle<String> name_handle(name); Handle<String> name_handle(name);
...@@ -393,7 +395,7 @@ Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) { ...@@ -393,7 +395,7 @@ Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) {
LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
&pending_exception); &pending_exception);
if (pending_exception) return Failure::Exception(); if (pending_exception) return Failure::Exception();
return this_handle->DeleteProperty(*name_handle); return this_handle->DeleteProperty(*name_handle, mode);
} }
...@@ -2120,7 +2122,7 @@ Object* JSObject::NormalizeElements() { ...@@ -2120,7 +2122,7 @@ Object* JSObject::NormalizeElements() {
} }
Object* JSObject::DeletePropertyPostInterceptor(String* name) { Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) {
// Check local property, ignore interceptor. // Check local property, ignore interceptor.
LookupResult result; LookupResult result;
LocalLookupRealNamedProperty(name, &result); LocalLookupRealNamedProperty(name, &result);
...@@ -2134,7 +2136,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name) { ...@@ -2134,7 +2136,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name) {
// Attempt to remove the property from the property dictionary. // Attempt to remove the property from the property dictionary.
Dictionary* dictionary = property_dictionary(); Dictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name); int entry = dictionary->FindStringEntry(name);
if (entry != -1) return dictionary->DeleteProperty(entry); if (entry != -1) return dictionary->DeleteProperty(entry, mode);
return Heap::true_value(); return Heap::true_value();
} }
...@@ -2164,13 +2166,15 @@ Object* JSObject::DeletePropertyWithInterceptor(String* name) { ...@@ -2164,13 +2166,15 @@ Object* JSObject::DeletePropertyWithInterceptor(String* name) {
return *v8::Utils::OpenHandle(*result); return *v8::Utils::OpenHandle(*result);
} }
} }
Object* raw_result = this_handle->DeletePropertyPostInterceptor(*name_handle); Object* raw_result =
this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(); RETURN_IF_SCHEDULED_EXCEPTION();
return raw_result; return raw_result;
} }
Object* JSObject::DeleteElementPostInterceptor(uint32_t index) { Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
DeleteMode mode) {
if (HasFastElements()) { if (HasFastElements()) {
uint32_t length = IsJSArray() ? uint32_t length = IsJSArray() ?
static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
...@@ -2183,7 +2187,7 @@ Object* JSObject::DeleteElementPostInterceptor(uint32_t index) { ...@@ -2183,7 +2187,7 @@ Object* JSObject::DeleteElementPostInterceptor(uint32_t index) {
ASSERT(!HasFastElements()); ASSERT(!HasFastElements());
Dictionary* dictionary = element_dictionary(); Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindNumberEntry(index);
if (entry != -1) return dictionary->DeleteProperty(entry); if (entry != -1) return dictionary->DeleteProperty(entry, mode);
return Heap::true_value(); return Heap::true_value();
} }
...@@ -2214,13 +2218,14 @@ Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { ...@@ -2214,13 +2218,14 @@ Object* JSObject::DeleteElementWithInterceptor(uint32_t index) {
ASSERT(result->IsBoolean()); ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result); return *v8::Utils::OpenHandle(*result);
} }
Object* raw_result = this_handle->DeleteElementPostInterceptor(index); Object* raw_result =
this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(); RETURN_IF_SCHEDULED_EXCEPTION();
return raw_result; return raw_result;
} }
Object* JSObject::DeleteElement(uint32_t index) { Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
// Check access rights if needed. // Check access rights if needed.
if (IsAccessCheckNeeded() && if (IsAccessCheckNeeded() &&
!Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
...@@ -2232,10 +2237,14 @@ Object* JSObject::DeleteElement(uint32_t index) { ...@@ -2232,10 +2237,14 @@ Object* JSObject::DeleteElement(uint32_t index) {
Object* proto = GetPrototype(); Object* proto = GetPrototype();
if (proto->IsNull()) return Heap::false_value(); if (proto->IsNull()) return Heap::false_value();
ASSERT(proto->IsJSGlobalObject()); ASSERT(proto->IsJSGlobalObject());
return JSGlobalObject::cast(proto)->DeleteElement(index); return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
} }
if (HasIndexedInterceptor()) { if (HasIndexedInterceptor()) {
// Skip interceptor if forcing deletion.
if (mode == FORCE_DELETION) {
return DeleteElementPostInterceptor(index, mode);
}
return DeleteElementWithInterceptor(index); return DeleteElementWithInterceptor(index);
} }
...@@ -2250,13 +2259,13 @@ Object* JSObject::DeleteElement(uint32_t index) { ...@@ -2250,13 +2259,13 @@ Object* JSObject::DeleteElement(uint32_t index) {
} else { } else {
Dictionary* dictionary = element_dictionary(); Dictionary* dictionary = element_dictionary();
int entry = dictionary->FindNumberEntry(index); int entry = dictionary->FindNumberEntry(index);
if (entry != -1) return dictionary->DeleteProperty(entry); if (entry != -1) return dictionary->DeleteProperty(entry, mode);
} }
return Heap::true_value(); return Heap::true_value();
} }
Object* JSObject::DeleteProperty(String* name) { Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
// ECMA-262, 3rd, 8.6.2.5 // ECMA-262, 3rd, 8.6.2.5
ASSERT(name->IsString()); ASSERT(name->IsString());
...@@ -2271,23 +2280,32 @@ Object* JSObject::DeleteProperty(String* name) { ...@@ -2271,23 +2280,32 @@ Object* JSObject::DeleteProperty(String* name) {
Object* proto = GetPrototype(); Object* proto = GetPrototype();
if (proto->IsNull()) return Heap::false_value(); if (proto->IsNull()) return Heap::false_value();
ASSERT(proto->IsJSGlobalObject()); ASSERT(proto->IsJSGlobalObject());
return JSGlobalObject::cast(proto)->DeleteProperty(name); return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
} }
uint32_t index = 0; uint32_t index = 0;
if (name->AsArrayIndex(&index)) { if (name->AsArrayIndex(&index)) {
return DeleteElement(index); return DeleteElement(index, mode);
} else { } else {
LookupResult result; LookupResult result;
LocalLookup(name, &result); LocalLookup(name, &result);
if (!result.IsValid()) return Heap::true_value(); if (!result.IsValid()) return Heap::true_value();
if (result.IsDontDelete()) return Heap::false_value(); // Ignore attributes if forcing a deletion.
if (result.IsDontDelete() && mode != FORCE_DELETION) {
return Heap::false_value();
}
// Check for interceptor. // Check for interceptor.
if (result.type() == INTERCEPTOR) { if (result.type() == INTERCEPTOR) {
// Skip interceptor if forcing a deletion.
if (mode == FORCE_DELETION) {
return DeletePropertyPostInterceptor(name, mode);
}
return DeletePropertyWithInterceptor(name); return DeletePropertyWithInterceptor(name);
} }
if (!result.IsLoaded()) { if (!result.IsLoaded()) {
return JSObject::cast(this)->DeleteLazyProperty(&result, name); return JSObject::cast(this)->DeleteLazyProperty(&result,
name,
mode);
} }
// Normalize object if needed. // Normalize object if needed.
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
...@@ -2295,7 +2313,7 @@ Object* JSObject::DeleteProperty(String* name) { ...@@ -2295,7 +2313,7 @@ Object* JSObject::DeleteProperty(String* name) {
// Make sure the properties are normalized before removing the entry. // Make sure the properties are normalized before removing the entry.
Dictionary* dictionary = property_dictionary(); Dictionary* dictionary = property_dictionary();
int entry = dictionary->FindStringEntry(name); int entry = dictionary->FindStringEntry(name);
if (entry != -1) return dictionary->DeleteProperty(entry); if (entry != -1) return dictionary->DeleteProperty(entry, mode);
return Heap::true_value(); return Heap::true_value();
} }
} }
...@@ -6943,9 +6961,12 @@ void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { ...@@ -6943,9 +6961,12 @@ void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
} }
Object* Dictionary::DeleteProperty(int entry) { Object* Dictionary::DeleteProperty(int entry, JSObject::DeleteMode mode) {
PropertyDetails details = DetailsAt(entry); PropertyDetails details = DetailsAt(entry);
if (details.IsDontDelete()) return Heap::false_value(); // Ignore attributes if forcing a deletion.
if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) {
return Heap::false_value();
}
SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0)); SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
ElementRemoved(); ElementRemoved();
return Heap::true_value(); return Heap::true_value();
......
...@@ -1275,9 +1275,12 @@ class JSObject: public HeapObject { ...@@ -1275,9 +1275,12 @@ class JSObject: public HeapObject {
return GetLocalPropertyAttribute(name) != ABSENT; return GetLocalPropertyAttribute(name) != ABSENT;
} }
Object* DeleteProperty(String* name); enum DeleteMode { NORMAL_DELETION, FORCE_DELETION };
Object* DeleteElement(uint32_t index); Object* DeleteProperty(String* name, DeleteMode mode);
Object* DeleteLazyProperty(LookupResult* result, String* name); Object* DeleteElement(uint32_t index, DeleteMode mode);
Object* DeleteLazyProperty(LookupResult* result,
String* name,
DeleteMode mode);
// Tests for the fast common case for property enumeration. // Tests for the fast common case for property enumeration.
bool IsSimpleEnum(); bool IsSimpleEnum();
...@@ -1519,10 +1522,10 @@ class JSObject: public HeapObject { ...@@ -1519,10 +1522,10 @@ class JSObject: public HeapObject {
Object* GetElementPostInterceptor(JSObject* receiver, uint32_t index); Object* GetElementPostInterceptor(JSObject* receiver, uint32_t index);
Object* DeletePropertyPostInterceptor(String* name); Object* DeletePropertyPostInterceptor(String* name, DeleteMode mode);
Object* DeletePropertyWithInterceptor(String* name); Object* DeletePropertyWithInterceptor(String* name);
Object* DeleteElementPostInterceptor(uint32_t index); Object* DeleteElementPostInterceptor(uint32_t index, DeleteMode mode);
Object* DeleteElementWithInterceptor(uint32_t index); Object* DeleteElementWithInterceptor(uint32_t index);
PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver, PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver,
...@@ -2057,7 +2060,7 @@ class Dictionary: public DictionaryBase { ...@@ -2057,7 +2060,7 @@ class Dictionary: public DictionaryBase {
int FindNumberEntry(uint32_t index); int FindNumberEntry(uint32_t index);
// Delete a property from the dictionary. // Delete a property from the dictionary.
Object* DeleteProperty(int entry); Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
// Type specific at put (default NONE attributes is used when adding). // Type specific at put (default NONE attributes is used when adding).
Object* AtStringPut(String* key, Object* value); Object* AtStringPut(String* key, Object* value);
...@@ -2628,7 +2631,7 @@ class Map: public HeapObject { ...@@ -2628,7 +2631,7 @@ class Map: public HeapObject {
static const int kHasInstanceCallHandler = 6; static const int kHasInstanceCallHandler = 6;
static const int kIsAccessCheckNeeded = 7; static const int kIsAccessCheckNeeded = 7;
// Bit positions for but field 2 // Bit positions for bit field 2
static const int kNeedsLoading = 0; static const int kNeedsLoading = 0;
private: private:
......
...@@ -2780,6 +2780,42 @@ Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object, ...@@ -2780,6 +2780,42 @@ Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
} }
Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
Handle<Object> key) {
HandleScope scope;
// Check if the given key is an array index.
uint32_t index;
if (Array::IndexFromObject(*key, &index)) {
// In Firefox/SpiderMonkey, Safari and Opera you can access the
// characters of a string using [] notation. In the case of a
// String object we just need to redirect the deletion to the
// underlying string if the index is in range. Since the
// underlying string does nothing with the deletion, we can ignore
// such deletions.
if (js_object->IsStringObjectWithCharacterAt(index)) {
return Heap::true_value();
}
return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
}
Handle<String> key_string;
if (key->IsString()) {
key_string = Handle<String>::cast(key);
} else {
// Call-back into JavaScript to convert the key to a string.
bool has_pending_exception = false;
Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
if (has_pending_exception) return Failure::Exception();
key_string = Handle<String>::cast(converted);
}
key_string->TryFlattenIfNotFlat();
return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
}
static Object* Runtime_SetProperty(Arguments args) { static Object* Runtime_SetProperty(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
...@@ -2831,7 +2867,7 @@ static Object* Runtime_DeleteProperty(Arguments args) { ...@@ -2831,7 +2867,7 @@ static Object* Runtime_DeleteProperty(Arguments args) {
CONVERT_CHECKED(JSObject, object, args[0]); CONVERT_CHECKED(JSObject, object, args[0]);
CONVERT_CHECKED(String, key, args[1]); CONVERT_CHECKED(String, key, args[1]);
return object->DeleteProperty(key); return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
} }
......
...@@ -387,6 +387,9 @@ class Runtime : public AllStatic { ...@@ -387,6 +387,9 @@ class Runtime : public AllStatic {
Handle<Object> value, Handle<Object> value,
PropertyAttributes attr); PropertyAttributes attr);
static Object* ForceDeleteObjectProperty(Handle<JSObject> object,
Handle<Object> key);
static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key); static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key);
// This function is used in FunctionNameUsing* tests. // This function is used in FunctionNameUsing* tests.
......
...@@ -115,7 +115,11 @@ function GlobalParseFloat(string) { ...@@ -115,7 +115,11 @@ function GlobalParseFloat(string) {
function GlobalEval(x) { function GlobalEval(x) {
if (!IS_STRING(x)) return x; if (!IS_STRING(x)) return x;
if (this !== global && this !== %GlobalReceiver(global)) { var global_receiver = %GlobalReceiver(global);
var this_is_global_receiver = (this === global_receiver);
var global_is_detached = (global === global_receiver);
if (!this_is_global_receiver || global_is_detached) {
throw new $EvalError('The "this" object passed to eval must ' + throw new $EvalError('The "this" object passed to eval must ' +
'be the global object from which eval originated'); 'be the global object from which eval originated');
} }
......
...@@ -4515,10 +4515,6 @@ THREADED_TEST(EvalAliasedDynamic) { ...@@ -4515,10 +4515,6 @@ THREADED_TEST(EvalAliasedDynamic) {
v8::HandleScope scope; v8::HandleScope scope;
LocalContext current; LocalContext current;
// This sets 'global' to the real global object (as opposed to the
// proxy). It is highly implementation dependent, so take care.
current->Global()->Set(v8_str("global"), current->Global()->GetPrototype());
// Tests where aliased eval can only be resolved dynamically. // Tests where aliased eval can only be resolved dynamically.
Local<Script> script = Local<Script> script =
Script::Compile(v8_str("function f(x) { " Script::Compile(v8_str("function f(x) { "
...@@ -4527,7 +4523,7 @@ THREADED_TEST(EvalAliasedDynamic) { ...@@ -4527,7 +4523,7 @@ THREADED_TEST(EvalAliasedDynamic) {
"}" "}"
"foo = 0;" "foo = 0;"
"result1 = f(new Object());" "result1 = f(new Object());"
"result2 = f(global);" "result2 = f(this);"
"var x = new Object();" "var x = new Object();"
"x.eval = function(x) { return 1; };" "x.eval = function(x) { return 1; };"
"result3 = f(x);")); "result3 = f(x);"));
...@@ -4542,7 +4538,7 @@ THREADED_TEST(EvalAliasedDynamic) { ...@@ -4542,7 +4538,7 @@ THREADED_TEST(EvalAliasedDynamic) {
" var bar = 2;" " var bar = 2;"
" with (x) { return eval('bar'); }" " with (x) { return eval('bar'); }"
"}" "}"
"f(global)")); "f(this)"));
script->Run(); script->Run();
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
try_catch.Reset(); try_catch.Reset();
...@@ -4629,6 +4625,44 @@ THREADED_TEST(CrossEval) { ...@@ -4629,6 +4625,44 @@ THREADED_TEST(CrossEval) {
} }
// Test that calling eval in a context which has been detached from
// its global throws an exception. This behavior is consistent with
// other JavaScript implementations.
THREADED_TEST(EvalInDetachedGlobal) {
v8::HandleScope scope;
v8::Persistent<Context> context0 = Context::New();
v8::Persistent<Context> context1 = Context::New();
// Setup function in context0 that uses eval from context0.
context0->Enter();
v8::Handle<v8::Value> fun =
CompileRun("var x = 42;"
"(function() {"
" var e = eval;"
" return function(s) { return e(s); }"
"})()");
context0->Exit();
// Put the function into context1 and call it before and after
// detaching the global. Before detaching, the call succeeds and
// after detaching and exception is thrown.
context1->Enter();
context1->Global()->Set(v8_str("fun"), fun);
v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
CHECK_EQ(42, x_value->Int32Value());
context0->DetachGlobal();
v8::TryCatch catcher;
x_value = CompileRun("fun('x')");
CHECK(x_value.IsEmpty());
CHECK(catcher.HasCaught());
context1->Exit();
context1.Dispose();
context0.Dispose();
}
THREADED_TEST(CrossLazyLoad) { THREADED_TEST(CrossLazyLoad) {
v8::HandleScope scope; v8::HandleScope scope;
LocalContext other; LocalContext other;
...@@ -6723,6 +6757,74 @@ TEST(ForceSetWithInterceptor) { ...@@ -6723,6 +6757,74 @@ TEST(ForceSetWithInterceptor) {
} }
THREADED_TEST(ForceDelete) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
LocalContext context(NULL, templ);
v8::Handle<v8::Object> global = context->Global();
// Ordinary properties
v8::Handle<v8::String> simple_property = v8::String::New("p");
global->Set(simple_property, v8::Int32::New(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 v8::Handle<v8::Boolean> ForceDeleteDeleter(
v8::Local<v8::String> name,
const v8::AccessorInfo& info) {
force_delete_interceptor_count++;
if (pass_on_delete) {
return v8::Handle<v8::Boolean>();
} else {
return v8::True();
}
}
THREADED_TEST(ForceDeleteWithInterceptor) {
force_delete_interceptor_count = 0;
pass_on_delete = false;
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
LocalContext context(NULL, templ);
v8::Handle<v8::Object> global = context->Global();
v8::Handle<v8::String> some_property = v8::String::New("a");
global->Set(some_property, v8::Integer::New(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);
}
v8::Persistent<Context> calling_context0; v8::Persistent<Context> calling_context0;
v8::Persistent<Context> calling_context1; v8::Persistent<Context> calling_context1;
v8::Persistent<Context> calling_context2; v8::Persistent<Context> calling_context2;
......
...@@ -553,7 +553,7 @@ TEST(ObjectProperties) { ...@@ -553,7 +553,7 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(first)); CHECK(obj->HasLocalProperty(first));
// delete first // delete first
CHECK(obj->DeleteProperty(first)); CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first)); CHECK(!obj->HasLocalProperty(first));
// add first and then second // add first and then second
...@@ -563,9 +563,9 @@ TEST(ObjectProperties) { ...@@ -563,9 +563,9 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(second)); CHECK(obj->HasLocalProperty(second));
// delete first and then second // delete first and then second
CHECK(obj->DeleteProperty(first)); CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(second)); CHECK(obj->HasLocalProperty(second));
CHECK(obj->DeleteProperty(second)); CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first)); CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second)); CHECK(!obj->HasLocalProperty(second));
...@@ -576,9 +576,9 @@ TEST(ObjectProperties) { ...@@ -576,9 +576,9 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(second)); CHECK(obj->HasLocalProperty(second));
// delete second and then first // delete second and then first
CHECK(obj->DeleteProperty(second)); CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(first)); CHECK(obj->HasLocalProperty(first));
CHECK(obj->DeleteProperty(first)); CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first)); CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second)); CHECK(!obj->HasLocalProperty(second));
......
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