Commit 6c39aefd authored by iposva@chromium.org's avatar iposva@chromium.org

Fix for issue 339:

- Move GetHiddenProperties functionality from object.cc to handle.cc to
  be more robust in the presence of GC in the middle of the function.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1924 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ade7d1ab
......@@ -273,7 +273,35 @@ Handle<Object> GetPrototype(Handle<Object> obj) {
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
bool create_if_needed) {
CALL_HEAP_FUNCTION(obj->GetHiddenProperties(create_if_needed), Object);
Handle<String> key = Factory::hidden_symbol();
if (obj->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 (and no other string has hash
// code zero) it will always occupy the first entry if present.
DescriptorArray* descriptors = obj->map()->instance_descriptors();
DescriptorReader r(descriptors);
if (!r.eos() && (r.GetKey() == *key) && r.IsProperty()) {
ASSERT(r.type() == FIELD);
return Handle<Object>(obj->FastPropertyAt(r.GetFieldIndex()));
}
}
// Only attempt to find the hidden properties in the local object and not
// in the prototype chain. Note that HasLocalProperty() can cause a GC in
// the general case in the presence of interceptors.
if (!obj->HasLocalProperty(*key)) {
// Hidden properties object not found. Allocate a new hidden properties
// object if requested. Otherwise return the undefined value.
if (create_if_needed) {
Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
return SetProperty(obj, key, hidden_obj, DONT_ENUM);
} else {
return Factory::undefined_value();
}
}
return GetProperty(obj, key);
}
......
......@@ -228,6 +228,9 @@ Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
Handle<Object> GetPrototype(Handle<Object> obj);
// 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.
Handle<Object> GetHiddenProperties(Handle<JSObject> obj, bool create_if_needed);
Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
......
......@@ -5145,42 +5145,6 @@ bool JSObject::HasLocalElement(uint32_t index) {
}
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 (and no other string has hash
// code zero) it will always occupy the first entry if present.
DescriptorArray* descriptors = this->map()->instance_descriptors();
DescriptorReader r(descriptors);
if (!r.eos() && (r.GetKey() == key) && r.IsProperty()) {
ASSERT(r.type() == FIELD);
return FastPropertyAt(r.GetFieldIndex());
}
}
// Only attempt to find the hidden properties in the local object and not
// in the prototype chain. Note that HasLocalProperty() can cause a GC in
// the general case, but in this case we know it won't hit an interceptor.
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() &&
......
......@@ -1286,11 +1286,6 @@ class JSObject: public HeapObject {
// 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);
......
......@@ -1327,6 +1327,38 @@ THREADED_TEST(HiddenProperties) {
}
static v8::Handle<Value> InterceptorForHiddenProperties(
Local<String> name, const AccessorInfo& info) {
// Make sure objects move.
bool saved_always_compact = i::FLAG_always_compact;
if (!i::FLAG_never_compact) {
i::FLAG_always_compact = true;
}
// The whole goal of this interceptor is to cause a GC during local property
// lookup.
i::Heap::CollectAllGarbage();
i::FLAG_always_compact = saved_always_compact;
return v8::Handle<Value>();
}
THREADED_TEST(HiddenPropertiesWithInterceptors) {
v8::HandleScope scope;
LocalContext context;
v8::Local<v8::String> key = v8_str("api-test::hidden-key");
// Associate an interceptor with an object and start setting hidden values.
Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
Local<v8::Function> function = fun_templ->GetFunction();
Local<v8::Object> obj = function->NewInstance();
CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
}
THREADED_TEST(External) {
v8::HandleScope scope;
int x = 3;
......
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