Push revisions 1527, 1539, 1540, 1541, 1550, 1551 from bleeding_edge to trunk.
git-svn-id: http://v8.googlecode.com/svn/trunk@1555 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 2a37310..785aa20 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1919,6 +1919,88 @@
}
+Local<v8::Object> v8::Object::Clone() {
+ ON_BAILOUT("v8::Object::Clone()", return Local<Object>());
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ EXCEPTION_PREAMBLE();
+ i::Handle<i::JSObject> result = i::Copy(self);
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(Local<Object>());
+ return Utils::ToLocal(result);
+}
+
+
+int v8::Object::GetIdentityHash() {
+ ON_BAILOUT("v8::Object::GetIdentityHash()", return 0);
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
+ i::Handle<i::Object> hash_symbol = i::Factory::identity_hash_symbol();
+ i::Handle<i::Object> hash = i::GetProperty(hidden_props, hash_symbol);
+ int hash_value;
+ if (hash->IsSmi()) {
+ hash_value = i::Smi::cast(*hash)->value();
+ } else {
+ hash_value = random() & i::Smi::kMaxValue; // Limit range to fit a smi.
+ i::SetProperty(hidden_props,
+ hash_symbol,
+ i::Handle<i::Object>(i::Smi::FromInt(hash_value)),
+ static_cast<PropertyAttributes>(None));
+ }
+ return hash_value;
+}
+
+
+bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
+ v8::Handle<v8::Value> value) {
+ ON_BAILOUT("v8::Object::SetHiddenValue()", return false);
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
+ i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+ i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+ EXCEPTION_PREAMBLE();
+ i::Handle<i::Object> obj = i::SetProperty(
+ hidden_props,
+ key_obj,
+ value_obj,
+ static_cast<PropertyAttributes>(None));
+ has_pending_exception = obj.is_null();
+ EXCEPTION_BAILOUT_CHECK(false);
+ return true;
+}
+
+
+v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
+ ON_BAILOUT("v8::Object::GetHiddenValue()", return Local<v8::Value>());
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
+ if (hidden_props->IsUndefined()) {
+ return v8::Local<v8::Value>();
+ }
+ i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+ EXCEPTION_PREAMBLE();
+ i::Handle<i::Object> result = i::GetProperty(hidden_props, key_obj);
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(v8::Local<v8::Value>());
+ if (result->IsUndefined()) {
+ return v8::Local<v8::Value>();
+ }
+ return Utils::ToLocal(result);
+}
+
+
+bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
+ ON_BAILOUT("v8::DeleteHiddenValue()", return false);
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::JSObject> hidden_props(
+ i::JSObject::cast(*i::GetHiddenProperties(self, false)));
+ if (hidden_props->IsUndefined()) {
+ return false;
+ }
+ i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+ return i::DeleteProperty(hidden_props, key_obj)->IsTrue();
+}
+
+
Local<v8::Object> Function::NewInstance() const {
return NewInstance(0, NULL);
}
@@ -2200,7 +2282,7 @@
const char* v8::V8::GetVersion() {
- return "1.1.1.2";
+ return "1.1.1.3";
}
diff --git a/src/factory.h b/src/factory.h
index 754c6da..1388de1 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -302,6 +302,10 @@
SYMBOL_LIST(SYMBOL_ACCESSOR)
#undef SYMBOL_ACCESSOR
+ static Handle<String> hidden_symbol() {
+ return Handle<String>(&Heap::hidden_symbol_);
+ }
+
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,
diff --git a/src/handles.cc b/src/handles.cc
index 48065dd..b6c59b0 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -52,44 +52,39 @@
}
-void** HandleScope::CreateHandle(void* value) {
+void** HandleScope::Extend() {
void** result = current_.next;
- if (result == current_.limit) {
- // Make sure there's at least one scope on the stack and that the
- // top of the scope stack isn't a barrier.
- if (current_.extensions < 0) {
- Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
- "Cannot create a handle without a HandleScope");
- return NULL;
- }
- HandleScopeImplementer* impl = HandleScopeImplementer::instance();
- // If there's more room in the last block, we use that. This is used
- // for fast creation of scopes after scope barriers.
- if (!impl->Blocks()->is_empty()) {
- void** limit = &impl->Blocks()->last()[kHandleBlockSize];
- if (current_.limit != limit) {
- current_.limit = limit;
- }
- }
- // If we still haven't found a slot for the handle, we extend the
- // current handle scope by allocating a new handle block.
- if (result == current_.limit) {
- // If there's a spare block, use it for growing the current scope.
- result = impl->GetSpareOrNewBlock();
- // Add the extension to the global list of blocks, but count the
- // extension as part of the current scope.
- impl->Blocks()->Add(result);
- current_.extensions++;
- current_.limit = &result[kHandleBlockSize];
+ ASSERT(result == current_.limit);
+ // Make sure there's at least one scope on the stack and that the
+ // top of the scope stack isn't a barrier.
+ if (current_.extensions < 0) {
+ Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
+ "Cannot create a handle without a HandleScope");
+ return NULL;
+ }
+ HandleScopeImplementer* impl = HandleScopeImplementer::instance();
+ // If there's more room in the last block, we use that. This is used
+ // for fast creation of scopes after scope barriers.
+ if (!impl->Blocks()->is_empty()) {
+ void** limit = &impl->Blocks()->last()[kHandleBlockSize];
+ if (current_.limit != limit) {
+ current_.limit = limit;
}
}
- // Update the current next field, set the value in the created
- // handle, and return the result.
- ASSERT(result < current_.limit);
- current_.next = result + 1;
- *result = value;
+ // If we still haven't found a slot for the handle, we extend the
+ // current handle scope by allocating a new handle block.
+ if (result == current_.limit) {
+ // If there's a spare block, use it for growing the current scope.
+ result = impl->GetSpareOrNewBlock();
+ // Add the extension to the global list of blocks, but count the
+ // extension as part of the current scope.
+ impl->Blocks()->Add(result);
+ current_.extensions++;
+ current_.limit = &result[kHandleBlockSize];
+ }
+
return result;
}
@@ -266,6 +261,12 @@
}
+Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
+ bool create_if_needed) {
+ CALL_HEAP_FUNCTION(obj->GetHiddenProperties(create_if_needed), Object);
+}
+
+
Handle<Object> DeleteElement(Handle<JSObject> obj,
uint32_t index) {
CALL_HEAP_FUNCTION(obj->DeleteElement(index), Object);
diff --git a/src/handles.h b/src/handles.h
index 21af7fc..c8e534e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -118,7 +118,16 @@
static int NumberOfHandles();
// Creates a new handle with the given value.
- static void** CreateHandle(void* value);
+ static inline void** CreateHandle(void* value) {
+ void** result = current_.next;
+ if (result == current_.limit) result = Extend();
+ // Update the current next field, set the value in the created
+ // handle, and return the result.
+ ASSERT(result < current_.limit);
+ current_.next = result + 1;
+ *result = value;
+ return result;
+ }
private:
// Prevent heap allocation or illegal handle scopes.
@@ -150,6 +159,9 @@
#endif
}
+ // Extend the handle scope making room for more handles.
+ static void** Extend();
+
// Deallocates any extensions used by the current scope.
static void DeleteExtensions();
@@ -211,6 +223,8 @@
Handle<Object> GetPrototype(Handle<Object> obj);
+Handle<Object> GetHiddenProperties(Handle<JSObject> obj, bool create_if_needed);
+
Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> prop);
diff --git a/src/heap.cc b/src/heap.cc
index 8159311..f384297 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -57,6 +57,8 @@
SYMBOL_LIST(SYMBOL_ALLOCATION)
#undef SYMBOL_ALLOCATION
+String* Heap::hidden_symbol_;
+
NewSpace Heap::new_space_;
OldSpace* Heap::old_pointer_space_ = NULL;
OldSpace* Heap::old_data_space_ = NULL;
@@ -1206,6 +1208,16 @@
SYMBOL_LIST(SYMBOL_INITIALIZE)
#undef SYMBOL_INITIALIZE
+ // Allocate the hidden symbol which is used to identify the hidden properties
+ // in JSObjects. The hash code has a special value so that it will not match
+ // the empty string when searching for the property. It cannot be part of the
+ // SYMBOL_LIST because it needs to be allocated manually with the special
+ // hash code in place. The hash code for the hidden_symbol is zero to ensure
+ // that it will always be at the first entry in property descriptors.
+ obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask);
+ if (obj->IsFailure()) return false;
+ hidden_symbol_ = String::cast(obj);
+
// Allocate the proxy for __proto__.
obj = AllocateProxy((Address) &Accessors::ObjectPrototype);
if (obj->IsFailure()) return false;
@@ -2650,6 +2662,7 @@
v->VisitPointer(bit_cast<Object**, String**>(&name##_));
SYMBOL_LIST(SYMBOL_ITERATE)
#undef SYMBOL_ITERATE
+ v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
SYNCHRONIZE_TAG("symbol");
Bootstrapper::Iterate(v);
diff --git a/src/heap.h b/src/heap.h
index 082bbb2..a1dd81e 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -195,7 +195,8 @@
V(space_symbol, " ") \
V(exec_symbol, "exec") \
V(zero_symbol, "0") \
- V(global_eval_symbol, "GlobalEval")
+ V(global_eval_symbol, "GlobalEval") \
+ V(identity_hash_symbol, "v8::IdentityHash")
// Forward declaration of the GCTracer class.
@@ -645,6 +646,10 @@
SYMBOL_LIST(SYMBOL_ACCESSOR)
#undef SYMBOL_ACCESSOR
+ // The hidden_symbol is special because it is the empty string, but does
+ // not match the empty string.
+ static String* hidden_symbol() { return hidden_symbol_; }
+
// Iterates over all roots in the heap.
static void IterateRoots(ObjectVisitor* v);
// Iterates over all strong roots in the heap.
@@ -888,6 +893,10 @@
SYMBOL_LIST(SYMBOL_DECLARATION)
#undef SYMBOL_DECLARATION
+ // The special hidden symbol which is an empty string, but does not match
+ // any string when looked up in properties.
+ static String* hidden_symbol_;
+
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
static GCCallback global_gc_prologue_callback_;
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 9aee342..941b84c 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2438,10 +2438,15 @@
uint32_t StringHasher::GetHash() {
+ // Get the calculated raw hash value and do some more bit ops to distribute
+ // the hash further. Ensure that we never return zero as the hash value.
uint32_t result = raw_running_hash_;
result += (result << 3);
result ^= (result >> 11);
result += (result << 15);
+ if (result == 0) {
+ result = 27;
+ }
return result;
}
diff --git a/src/objects.cc b/src/objects.cc
index b8228f0..44ebb3f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -3113,8 +3113,12 @@
int DescriptorArray::LinearSearch(String* name, int len) {
+ uint32_t hash = name->Hash();
for (int number = 0; number < len; number++) {
- if (name->Equals(GetKey(number)) && !is_null_descriptor(number)) {
+ String* entry = GetKey(number);
+ if ((entry->Hash() == hash) &&
+ name->Equals(entry) &&
+ !is_null_descriptor(number)) {
return number;
}
}
@@ -4187,7 +4191,7 @@
uint32_t String::ComputeAndSetHash() {
- // Should only be call if hash code has not yet been computed.
+ // Should only be called if hash code has not yet been computed.
ASSERT(!(length_field() & kHashComputedMask));
// Compute the hash code.
@@ -4199,7 +4203,9 @@
// Check the hash code is there.
ASSERT(length_field() & kHashComputedMask);
- return field >> kHashShift;
+ uint32_t result = field >> kHashShift;
+ ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
+ return result;
}
@@ -5081,6 +5087,45 @@
}
+Object* JSObject::GetHiddenProperties(bool create_if_needed) {
+ String* key = Heap::hidden_symbol();
+ if (this->HasFastProperties()) {
+ // If the object has fast properties, check whether the first slot in the
+ // descriptor array matches the hidden symbol. Since the hidden symbols
+ // hash code is zero it will always occupy the first entry if present.
+ DescriptorArray* descriptors = this->map()->instance_descriptors();
+ if (descriptors->number_of_descriptors() > 0) {
+ if (descriptors->GetKey(0) == key) {
+#ifdef DEBUG
+ PropertyDetails details(descriptors->GetDetails(0));
+ ASSERT(details.type() == FIELD);
+#endif // DEBUG
+ Object* value = descriptors->GetValue(0);
+ return FastPropertyAt(Descriptor::IndexFromValue(value));
+ }
+ }
+ }
+
+ // Only attempt to find the hidden properties in the local object and not
+ // in the prototype chain.
+ if (!this->HasLocalProperty(key)) {
+ // Hidden properties object not found. Allocate a new hidden properties
+ // object if requested. Otherwise return the undefined value.
+ if (create_if_needed) {
+ Object* obj = Heap::AllocateJSObject(
+ Top::context()->global_context()->object_function());
+ if (obj->IsFailure()) {
+ return obj;
+ }
+ return this->SetProperty(key, obj, DONT_ENUM);
+ } else {
+ return Heap::undefined_value();
+ }
+ }
+ return this->GetProperty(key);
+}
+
+
bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
@@ -5927,13 +5972,20 @@
// StringKey simply carries a string object as key.
class StringKey : public HashTableKey {
public:
- explicit StringKey(String* string) : string_(string) { }
+ explicit StringKey(String* string) :
+ string_(string),
+ hash_(StringHash(string)) { }
bool IsMatch(Object* string) {
+ // We know that all entries in a hash table had their hash keys created.
+ // Use that knowledge to have fast failure.
+ if (hash_ != StringHash(string)) {
+ return false;
+ }
return string_->Equals(String::cast(string));
}
- uint32_t Hash() { return StringHash(string_); }
+ uint32_t Hash() { return hash_; }
HashFunction GetHashFunction() { return StringHash; }
@@ -5946,6 +5998,7 @@
bool IsStringKey() { return true; }
String* string_;
+ uint32_t hash_;
};
@@ -6072,7 +6125,9 @@
static_cast<unsigned>(string_.length()));
chars_ = buffer.Length();
length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
- return length_field_ >> String::kHashShift;
+ uint32_t result = length_field_ >> String::kHashShift;
+ ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
+ return result;
}
Object* GetObject() {
diff --git a/src/objects.h b/src/objects.h
index 28df02a..c38aa38 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1243,6 +1243,11 @@
// Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype();
+ // Return the object's hidden properties object. If the object has no hidden
+ // properties and create_if_needed is true, then a new hidden property object
+ // will be allocated. Otherwise the Heap::undefined_value is returned.
+ Object* GetHiddenProperties(bool create_if_needed);
+
// Tells whether the index'th element is present.
inline bool HasElement(uint32_t index);
bool HasElementWithReceiver(JSObject* receiver, uint32_t index);
diff --git a/src/spaces.h b/src/spaces.h
index 3d13219..8a3dc5b 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1481,7 +1481,7 @@
MapSpaceFreeList free_list_;
// An array of page start address in a map space.
- Address page_addresses_[kMaxMapPageIndex];
+ Address page_addresses_[kMaxMapPageIndex + 1];
public:
TRACK_MEMORY("MapSpace")
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index b7ef311..b472eab 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -656,9 +656,8 @@
Object* LoadCallbackProperty(Arguments args) {
Handle<JSObject> recv = args.at<JSObject>(0);
AccessorInfo* callback = AccessorInfo::cast(args[1]);
- v8::AccessorGetter fun =
- FUNCTION_CAST<v8::AccessorGetter>(
- v8::ToCData<Address>(callback->getter()));
+ Address getter_address = v8::ToCData<Address>(callback->getter());
+ v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
ASSERT(fun != NULL);
Handle<String> name = args.at<String>(2);
Handle<JSObject> holder = args.at<JSObject>(3);
@@ -669,10 +668,9 @@
// locations of the arguments to this function maybe we don't have
// to explicitly create the structure but can just pass a pointer
// into the stack.
- v8::AccessorInfo info(
- v8::Utils::ToLocal(recv),
- v8::Utils::ToLocal(data),
- v8::Utils::ToLocal(holder));
+ v8::AccessorInfo info(v8::Utils::ToLocal(recv),
+ v8::Utils::ToLocal(data),
+ v8::Utils::ToLocal(holder));
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
@@ -680,30 +678,25 @@
result = fun(v8::Utils::ToLocal(name), info);
}
RETURN_IF_SCHEDULED_EXCEPTION();
- if (result.IsEmpty()) {
- return Heap::undefined_value();
- } else {
- return *v8::Utils::OpenHandle(*result);
- }
+ if (result.IsEmpty()) return Heap::undefined_value();
+ return *v8::Utils::OpenHandle(*result);
}
Object* StoreCallbackProperty(Arguments args) {
Handle<JSObject> recv = args.at<JSObject>(0);
AccessorInfo* callback = AccessorInfo::cast(args[1]);
- v8::AccessorSetter fun =
- FUNCTION_CAST<v8::AccessorSetter>(
- v8::ToCData<Address>(callback->setter()));
+ Address setter_address = v8::ToCData<Address>(callback->setter());
+ v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
ASSERT(fun != NULL);
Handle<String> name = args.at<String>(2);
Handle<Object> value = args.at<Object>(3);
HandleScope scope;
Handle<Object> data(callback->data());
LOG(ApiNamedPropertyAccess("store", *recv, *name));
- v8::AccessorInfo info(
- v8::Utils::ToLocal(recv),
- v8::Utils::ToLocal(data),
- v8::Utils::ToLocal(recv));
+ v8::AccessorInfo info(v8::Utils::ToLocal(recv),
+ v8::Utils::ToLocal(data),
+ v8::Utils::ToLocal(recv));
{
// Leaving JavaScript.
VMState state(OTHER);
@@ -715,28 +708,17 @@
Object* LoadInterceptorProperty(Arguments args) {
- HandleScope scope;
- Handle<JSObject> recv = args.at<JSObject>(0);
- Handle<JSObject> holder = args.at<JSObject>(1);
- Handle<String> name = args.at<String>(2);
+ JSObject* recv = JSObject::cast(args[0]);
+ JSObject* holder = JSObject::cast(args[1]);
+ String* name = String::cast(args[2]);
ASSERT(holder->HasNamedInterceptor());
PropertyAttributes attr = NONE;
- Handle<Object> result = GetPropertyWithInterceptor(recv, holder, name, &attr);
+ Object* result = holder->GetPropertyWithInterceptor(recv, name, &attr);
- // GetPropertyWithInterceptor already converts a scheduled exception
- // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
-
- // Make sure to propagate exceptions.
- if (result.is_null()) {
- // Failure::Exception is converted to a null handle in the
- // handle-based methods such as SetProperty. We therefore need
- // to convert null handles back to exceptions.
- ASSERT(Top::has_pending_exception());
- return Failure::Exception();
- }
+ if (result->IsFailure()) return result;
// If the property is present, return it.
- if (attr != ABSENT) return *result;
+ if (attr != ABSENT) return result;
// If the top frame is an internal frame, this is really a call
// IC. In this case, we simply return the undefined result which
@@ -744,43 +726,38 @@
// function.
StackFrameIterator it;
it.Advance(); // skip exit frame
- if (it.frame()->is_internal()) return *result;
+ if (it.frame()->is_internal()) return result;
// If the load is non-contextual, just return the undefined result.
// Note that both keyed and non-keyed loads may end up here, so we
// can't use either LoadIC or KeyedLoadIC constructors.
IC ic(IC::NO_EXTRA_FRAME);
ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
- if (!ic.is_contextual()) return *result;
+ if (!ic.is_contextual()) return result;
// Throw a reference error.
- Handle<Object> error =
- Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
- return Top::Throw(*error);
+ {
+ HandleScope scope;
+ // We cannot use the raw name pointer here since getting the
+ // property might cause a GC. However, we can get the name from
+ // the stack using the arguments object.
+ Handle<String> name_handle = args.at<String>(2);
+ Handle<Object> error =
+ Factory::NewReferenceError("not_defined",
+ HandleVector(&name_handle, 1));
+ return Top::Throw(*error);
+ }
}
Object* StoreInterceptorProperty(Arguments args) {
- HandleScope scope;
- Handle<JSObject> recv = args.at<JSObject>(0);
- Handle<String> name = args.at<String>(1);
- Handle<Object> value = args.at<Object>(2);
+ JSObject* recv = JSObject::cast(args[0]);
+ String* name = String::cast(args[1]);
+ Object* value = args[2];
ASSERT(recv->HasNamedInterceptor());
PropertyAttributes attr = NONE;
- Handle<Object> result = SetPropertyWithInterceptor(recv, name, value, attr);
-
- // SetPropertyWithInterceptor already converts a scheduled exception
- // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
-
- // Make sure to propagate exceptions.
- if (result.is_null()) {
- // Failure::Exception is converted to a null handle in the
- // handle-based methods such as SetProperty. We therefore need
- // to convert null handles back to exceptions.
- ASSERT(Top::has_pending_exception());
- return Failure::Exception();
- }
- return *result;
+ Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
+ return result;
}