Author: whe...@chromium.org Date: Wed Jun 10 08:33:31 2009 New Revision: 2138
Modified: branches/bleeding_edge/src/objects.cc branches/bleeding_edge/src/objects.h branches/bleeding_edge/test/cctest/test-api.cc Log: Make JSObjects with both indexed interceptors and indexed accessors work safely. Review URL: http://codereview.chromium.org/118499 Modified: branches/bleeding_edge/src/objects.cc ============================================================================== --- branches/bleeding_edge/src/objects.cc (original) +++ branches/bleeding_edge/src/objects.cc Wed Jun 10 08:33:31 2009 @@ -5203,27 +5203,6 @@ } -Object* JSObject::SetElementPostInterceptor(uint32_t index, Object* value) { - if (HasFastElements()) return SetFastElement(index, value); - - // Dictionary case. - ASSERT(!HasFastElements()); - - FixedArray* elms = FixedArray::cast(elements()); - Object* result = Dictionary::cast(elms)->AtNumberPut(index, value); - if (result->IsFailure()) return result; - if (elms != FixedArray::cast(result)) { - set_elements(FixedArray::cast(result)); - } - - if (IsJSArray()) { - return JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value); - } - - return value; -} - - Object* JSObject::SetElementWithInterceptor(uint32_t index, Object* value) { // Make sure that the top context does not change when doing // callbacks or interceptor calls. @@ -5250,7 +5229,7 @@ if (!result.IsEmpty()) return *value_handle; } Object* raw_result = - this_handle->SetElementPostInterceptor(index, *value_handle); + this_handle->SetElementWithoutInterceptor(index, *value_handle); RETURN_IF_SCHEDULED_EXCEPTION(); return raw_result; } @@ -5332,6 +5311,11 @@ return SetElementWithInterceptor(index, value); } + return SetElementWithoutInterceptor(index, value); +} + + +Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { // Fast case. if (HasFastElements()) return SetFastElement(index, value); @@ -5438,7 +5422,21 @@ Dictionary* dictionary = element_dictionary(); int entry = dictionary->FindNumberEntry(index); if (entry != -1) { - return dictionary->ValueAt(entry); + Object* element = dictionary->ValueAt(entry); + PropertyDetails details = dictionary->DetailsAt(entry); + if (details.type() == CALLBACKS) { + // Only accessors allowed as elements. + FixedArray* structure = FixedArray::cast(element); + Object* getter = structure->get(kGetterIndex); + if (getter->IsJSFunction()) { + return GetPropertyWithDefinedGetter(receiver, + JSFunction::cast(getter)); + } else { + // Getter is not a function. + return Heap::undefined_value(); + } + } + return element; } } Modified: branches/bleeding_edge/src/objects.h ============================================================================== --- branches/bleeding_edge/src/objects.h (original) +++ branches/bleeding_edge/src/objects.h Wed Jun 10 08:33:31 2009 @@ -1531,7 +1531,7 @@ private: Object* SetElementWithInterceptor(uint32_t index, Object* value); - Object* SetElementPostInterceptor(uint32_t index, Object* value); + Object* SetElementWithoutInterceptor(uint32_t index, Object* value); Object* GetElementPostInterceptor(JSObject* receiver, uint32_t index); Modified: branches/bleeding_edge/test/cctest/test-api.cc ============================================================================== --- branches/bleeding_edge/test/cctest/test-api.cc (original) +++ branches/bleeding_edge/test/cctest/test-api.cc Wed Jun 10 08:33:31 2009 @@ -551,6 +551,7 @@ CHECK(isymbol->IsSymbol()); } i::Heap::CollectAllGarbage(); + i::Heap::CollectAllGarbage(); } @@ -568,6 +569,7 @@ CHECK(isymbol->IsSymbol()); } i::Heap::CollectAllGarbage(); + i::Heap::CollectAllGarbage(); } @@ -2281,7 +2283,7 @@ } -THREADED_TEST(NamedInterceporPropertyRead) { +THREADED_TEST(NamedInterceptorPropertyRead) { v8::HandleScope scope; Local<ObjectTemplate> templ = ObjectTemplate::New(); templ->SetNamedPropertyHandler(XPropertyGetter); @@ -2293,6 +2295,58 @@ CHECK_EQ(result, v8_str("x")); } } + + +static v8::Handle<Value> IndexedPropertyGetter(uint32_t index, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + if (index == 37) { + return v8::Handle<Value>(v8_num(625)); + } + return v8::Handle<Value>(); +} + + +static v8::Handle<Value> IndexedPropertySetter(uint32_t index, + Local<Value> value, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + if (index == 39) { + return value; + } + return v8::Handle<Value>(); +} + + +THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { + v8::HandleScope scope; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->SetIndexedPropertyHandler(IndexedPropertyGetter, + IndexedPropertySetter); + LocalContext context; + context->Global()->Set(v8_str("obj"), templ->NewInstance()); + Local<Script> getter_script = Script::Compile(v8_str( + "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];")); + Local<Script> setter_script = Script::Compile(v8_str( + "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" + "obj[17] = 23;" + "obj.foo;")); + Local<Script> interceptor_setter_script = Script::Compile(v8_str( + "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" + "obj[39] = 47;" + "obj.foo;")); // This setter should not run, due to the interceptor. + Local<Script> interceptor_getter_script = Script::Compile(v8_str( + "obj[37];")); + Local<Value> result = getter_script->Run(); + CHECK_EQ(v8_num(5), result); + result = setter_script->Run(); + CHECK_EQ(v8_num(23), result); + result = interceptor_setter_script->Run(); + CHECK_EQ(v8_num(23), result); + result = interceptor_getter_script->Run(); + CHECK_EQ(v8_num(625), result); +} + THREADED_TEST(MultiContexts) { v8::HandleScope scope; --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list v8-dev@googlegroups.com http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---