diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index d3e6492479..6314955b13 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -1720,11 +1720,13 @@ MaybeObject* JSObject::AddProperty(String* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode) { + JSReceiver::StoreFromKeyed store_mode, + ExtensibilityCheck extensibility_check) { ASSERT(!IsJSGlobalProxy()); Map* map_of_this = map(); Heap* heap = GetHeap(); - if (!map_of_this->is_extensible()) { + if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && + !map_of_this->is_extensible()) { if (strict_mode == kNonStrictMode) { return value; } else { @@ -1763,7 +1765,8 @@ MaybeObject* JSObject::SetPropertyPostInterceptor( String* name, Object* value, PropertyAttributes attributes, - StrictModeFlag strict_mode) { + StrictModeFlag strict_mode, + ExtensibilityCheck extensibility_check) { // Check local property, ignore interceptor. LookupResult result(GetIsolate()); LocalLookupRealNamedProperty(name, &result); @@ -1778,7 +1781,8 @@ MaybeObject* JSObject::SetPropertyPostInterceptor( SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done); if (done) return result_object; // Add a new real property. - return AddProperty(name, value, attributes, strict_mode); + return AddProperty(name, value, attributes, strict_mode, + MAY_BE_STORE_FROM_KEYED, extensibility_check); } @@ -1935,7 +1939,8 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( this_handle->SetPropertyPostInterceptor(*name_handle, *value_handle, attributes, - strict_mode); + strict_mode, + PERFORM_EXTENSIBILITY_CHECK); RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } @@ -3664,11 +3669,14 @@ MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize); StringDictionary* dictionary; if (!dict_alloc->To(&dictionary)) return dict_alloc; - // Using AddProperty or SetPropertyPostInterceptor here could fail, because - // object might be non-extensible. - return HasFastProperties() - ? AddFastProperty(GetHeap()->hidden_symbol(), dictionary, DONT_ENUM) - : AddSlowProperty(GetHeap()->hidden_symbol(), dictionary, DONT_ENUM); + MaybeObject* store_result = + SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), + dictionary, + DONT_ENUM, + kNonStrictMode, + OMIT_EXTENSIBILITY_CHECK); + if (store_result->IsFailure()) return store_result; + return dictionary; } @@ -3697,7 +3705,8 @@ MaybeObject* JSObject::SetHiddenPropertiesDictionary( SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), dictionary, DONT_ENUM, - kNonStrictMode); + kNonStrictMode, + OMIT_EXTENSIBILITY_CHECK); if (store_result->IsFailure()) return store_result; return this; } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 9aac37fcce..15ecdd1412 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -1369,6 +1369,13 @@ class JSReceiver: public HeapObject { CERTAINLY_NOT_STORE_FROM_KEYED }; + // Internal properties (e.g. the hidden properties dictionary) might + // be added even though the receiver is non-extensible. + enum ExtensibilityCheck { + PERFORM_EXTENSIBILITY_CHECK, + OMIT_EXTENSIBILITY_CHECK + }; + // Casting. static inline JSReceiver* cast(Object* obj); @@ -1567,7 +1574,8 @@ class JSObject: public JSReceiver { String* name, Object* value, PropertyAttributes attributes, - StrictModeFlag strict_mode); + StrictModeFlag strict_mode, + ExtensibilityCheck extensibility_check); static Handle SetLocalPropertyIgnoreAttributes( Handle object, @@ -1959,7 +1967,8 @@ class JSObject: public JSReceiver { Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED); + StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED, + ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK); // Convert the object to use the canonical dictionary // representation. If the object is expected to have additional properties diff --git a/deps/v8/test/mjsunit/regress/regress-2156.js b/deps/v8/test/mjsunit/regress/regress-2156.js new file mode 100644 index 0000000000..3482571130 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2156.js @@ -0,0 +1,39 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --allow-natives-syntax --harmony-collections + +var key1 = {}; +var key2 = {}; +var map = new WeakMap; + +// Adding hidden properties preserves map sharing. Putting the key into +// a WeakMap will cause the first hidden property to be added. +assertTrue(%HaveSameMap(key1, key2)); +map.set(key1, 1); +map.set(key2, 2); +assertTrue(%HaveSameMap(key1, key2));