Revision: 12277
Author: [email protected]
Date: Wed Aug 8 07:43:45 2012
Log: Fix handling of accessors on trunk. This is a combination of
r12271, r12264 and r12247, and is intended to fix bugs 140473,
140430 and 138388. Unfortunately it probably breaks the MIPS
port.
Review URL: https://chromiumcodereview.appspot.com/10827220
http://code.google.com/p/v8/source/detail?r=12277
Modified:
/trunk/src/arm/stub-cache-arm.cc
/trunk/src/bootstrapper.cc
/trunk/src/heap.cc
/trunk/src/hydrogen-instructions.cc
/trunk/src/hydrogen.cc
/trunk/src/ia32/stub-cache-ia32.cc
/trunk/src/ic.cc
/trunk/src/objects-inl.h
/trunk/src/objects.cc
/trunk/src/objects.h
/trunk/src/stub-cache.h
/trunk/src/type-info.cc
/trunk/src/version.cc
/trunk/src/x64/stub-cache-x64.cc
/trunk/test/cctest/test-api.cc
=======================================
--- /trunk/src/arm/stub-cache-arm.cc Fri Jul 27 01:03:27 2012
+++ /trunk/src/arm/stub-cache-arm.cc Wed Aug 8 07:43:45 2012
@@ -1228,6 +1228,42 @@
__ LoadHeapObject(r0, value);
__ Ret();
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ Register index = scratch2;
+ __ ldr(dictionary, FieldMemOperand(receiver,
JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ index, // Set if we
hit.
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, check that the value is
the
+ // callback.
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ add(scratch1, dictionary, Operand(kValueOffset - kHeapObjectTag));
+ __ ldr(scratch3, MemOperand(scratch1, index, LSL, kPointerSizeLog2));
+ __ cmp(scratch3, Operand(callback));
+ __ b(ne, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1247,6 +1283,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Build AccessorInfo::args_ list on the stack and push property name
below
// the exit frame to make GC aware of them and store pointers to them.
__ push(receiver);
=======================================
--- /trunk/src/bootstrapper.cc Tue Jul 24 00:59:48 2012
+++ /trunk/src/bootstrapper.cc Wed Aug 8 07:43:45 2012
@@ -747,6 +747,7 @@
}
js_global_function->initial_map()->set_is_hidden_prototype();
+ js_global_function->initial_map()->set_dictionary_map(true);
Handle<GlobalObject> inner_global =
factory()->NewGlobalObject(js_global_function);
if (inner_global_out != NULL) {
@@ -1431,6 +1432,7 @@
Handle<String> name = factory()->LookupAsciiSymbol("builtins");
builtins_fun->shared()->set_instance_class_name(*name);
+ builtins_fun->initial_map()->set_dictionary_map(true);
// Allocate the builtins object.
Handle<JSBuiltinsObject> builtins =
=======================================
--- /trunk/src/heap.cc Wed Aug 1 04:14:42 2012
+++ /trunk/src/heap.cc Wed Aug 8 07:43:45 2012
@@ -2424,6 +2424,7 @@
if (!maybe_obj->ToObject(&obj)) return false;
}
Map* global_context_map = Map::cast(obj);
+ global_context_map->set_dictionary_map(true);
global_context_map->set_visitor_id(StaticVisitorBase::kVisitGlobalContext);
set_global_context_map(global_context_map);
@@ -4108,6 +4109,7 @@
MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
ASSERT(constructor->has_initial_map());
Map* map = constructor->initial_map();
+ ASSERT(map->is_dictionary_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
@@ -4158,6 +4160,7 @@
Map* new_map;
MaybeObject* maybe_map = map->CopyDropDescriptors();
if (!maybe_map->To(&new_map)) return maybe_map;
+ new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(new_map);
=======================================
--- /trunk/src/hydrogen-instructions.cc Tue Jul 24 00:59:48 2012
+++ /trunk/src/hydrogen-instructions.cc Wed Aug 8 07:43:45 2012
@@ -1682,6 +1682,7 @@
if (current->IsJSGlobalProxy() ||
current->IsGlobalObject() ||
!current->IsJSObject() ||
+ JSObject::cast(current)->map()->has_named_interceptor() ||
JSObject::cast(current)->IsAccessCheckNeeded() ||
!JSObject::cast(current)->HasFastProperties()) {
return false;
@@ -1743,6 +1744,11 @@
break;
}
} else if (lookup.IsCacheable() &&
+ // For dicts the lookup on the map will fail, but the
object may
+ // contain the property so we cannot generate a negative
lookup
+ // (which would just be a map check and return undefined).
+ !map->is_dictionary_map() &&
+ !map->has_named_interceptor() &&
PrototypeChainCanNeverResolve(map, name)) {
negative_lookups.Add(types->at(i), zone);
}
=======================================
--- /trunk/src/hydrogen.cc Fri Aug 3 03:44:23 2012
+++ /trunk/src/hydrogen.cc Wed Aug 8 07:43:45 2012
@@ -5215,8 +5215,13 @@
HInstruction* instr = NULL;
SmallMapList* types = expr->GetReceiverTypes();
- if (expr->IsMonomorphic()) {
- Handle<Map> map = types->first();
+ bool monomorphic = expr->IsMonomorphic();
+ Handle<Map> map;
+ if (monomorphic) {
+ map = types->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -5392,8 +5397,14 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
HInstruction* load;
- if (prop->IsMonomorphic()) {
+ bool monomorphic = prop->IsMonomorphic();
+ if (monomorphic) {
map = prop->GetReceiverTypes()->first();
+ // We can't generate code for a monomorphic dict mode load so
+ // just pretend it is not monomorphic.
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -5416,7 +5427,7 @@
if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
HInstruction* store;
- if (map.is_null()) {
+ if (!monomorphic) {
// If we don't know the monomorphic type, do a generic store.
CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, instr));
} else {
@@ -5717,6 +5728,7 @@
Property* expr,
Handle<Map> map) {
// Handle a load from a known field.
+ ASSERT(!map->is_dictionary_map());
LookupResult lookup(isolate());
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsField()) {
@@ -6350,8 +6362,13 @@
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
SmallMapList* types = expr->GetReceiverTypes();
+ bool monomorphic = expr->IsMonomorphic();
+ Handle<Map> map;
if (expr->IsMonomorphic()) {
- Handle<Map> map = types->first();
+ map = types->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -7860,8 +7877,12 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
HInstruction* load;
- if (prop->IsMonomorphic()) {
+ bool monomorphic = prop->IsMonomorphic();
+ if (monomorphic) {
map = prop->GetReceiverTypes()->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -7879,7 +7900,7 @@
input = Pop();
HInstruction* store;
- if (map.is_null()) {
+ if (!monomorphic) {
// If we don't know the monomorphic type, do a generic store.
CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, after));
} else {
=======================================
--- /trunk/src/ia32/stub-cache-ia32.cc Thu Jul 5 01:22:44 2012
+++ /trunk/src/ia32/stub-cache-ia32.cc Wed Aug 8 07:43:45 2012
@@ -1050,6 +1050,42 @@
GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
__ ret(0);
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ scratch2,
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, scratch2 contains the
+ // index into the dictionary. Check that the value is the callback.
+ Register index = scratch2;
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ mov(scratch3,
+ Operand(dictionary, index, times_4, kValueOffset -
kHeapObjectTag));
+ __ cmp(scratch3, callback);
+ __ j(not_equal, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1069,6 +1105,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Insert additional parameters into the stack frame above return
address.
ASSERT(!scratch3.is(reg));
__ pop(scratch3); // Get return address to place it below.
=======================================
--- /trunk/src/ic.cc Tue Jul 24 00:59:48 2012
+++ /trunk/src/ic.cc Wed Aug 8 07:43:45 2012
@@ -989,7 +989,6 @@
if (callback->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->getter()) == 0) return;
- if (!receiver->HasFastProperties()) return;
if (!info->IsCompatibleReceiver(*receiver)) return;
code = isolate()->stub_cache()->ComputeLoadCallback(
name, receiver, holder, info);
@@ -997,7 +996,6 @@
Handle<Object>
getter(Handle<AccessorPair>::cast(callback)->getter());
if (!getter->IsJSFunction()) return;
if (holder->IsGlobalObject()) return;
- if (!receiver->HasFastProperties()) return;
code = isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, Handle<JSFunction>::cast(getter));
} else {
@@ -1266,7 +1264,7 @@
Handle<AccessorInfo> callback =
Handle<AccessorInfo>::cast(callback_object);
if (v8::ToCData<Address>(callback->getter()) == 0) return;
- if (!receiver->HasFastProperties()) return;
+ if (!holder->HasFastProperties()) return;
if (!callback->IsCompatibleReceiver(*receiver)) return;
code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
name, receiver, holder, callback);
@@ -1325,7 +1323,9 @@
// that we explicitly exclude native accessors for now, because the
stubs
// are not yet prepared for this scenario.
receiver->Lookup(*name, lookup);
- if (!lookup->IsPropertyCallbacks()) return false;
+ if (!lookup->IsPropertyCallbacks()) {
+ return false;
+ }
Handle<Object> callback(lookup->GetCallbackObject());
return callback->IsAccessorPair() && StoreICableLookup(lookup);
}
@@ -1487,9 +1487,10 @@
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject());
if (callback->IsAccessorInfo()) {
+ ASSERT(*holder == *receiver); // LookupForWrite checks this.
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->setter()) == 0) return;
- if (!receiver->HasFastProperties()) return;
+ if (!holder->HasFastProperties()) return;
ASSERT(info->IsCompatibleReceiver(*receiver));
code = isolate()->stub_cache()->ComputeStoreCallback(
name, receiver, info, strict_mode);
@@ -1497,7 +1498,7 @@
Handle<Object>
setter(Handle<AccessorPair>::cast(callback)->setter());
if (!setter->IsJSFunction()) return;
if (holder->IsGlobalObject()) return;
- if (!receiver->HasFastProperties()) return;
+ if (!holder->HasFastProperties()) return;
code = isolate()->stub_cache()->ComputeStoreViaSetter(
name, receiver, holder, Handle<JSFunction>::cast(setter),
strict_mode);
=======================================
--- /trunk/src/objects-inl.h Fri Jul 27 01:03:27 2012
+++ /trunk/src/objects-inl.h Wed Aug 8 07:43:45 2012
@@ -1608,6 +1608,7 @@
bool JSObject::HasFastProperties() {
+ ASSERT(properties()->IsDictionary() == map()->is_dictionary_map());
return !properties()->IsDictionary();
}
@@ -3006,10 +3007,21 @@
void Map::set_is_shared(bool value) {
set_bit_field3(IsShared::update(bit_field3(), value));
}
+
bool Map::is_shared() {
return IsShared::decode(bit_field3());
}
+
+
+void Map::set_dictionary_map(bool value) {
+ set_bit_field3(DictionaryMap::update(bit_field3(), value));
+}
+
+
+bool Map::is_dictionary_map() {
+ return DictionaryMap::decode(bit_field3());
+}
JSFunction* Map::unchecked_constructor() {
=======================================
--- /trunk/src/objects.cc Wed Aug 1 04:14:42 2012
+++ /trunk/src/objects.cc Wed Aug 8 07:43:45 2012
@@ -516,6 +516,7 @@
MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ ASSERT(new_map->is_dictionary_map());
set_map(new_map);
}
JSGlobalPropertyCell* cell =
@@ -3218,6 +3219,7 @@
fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
+ ASSERT(Map::cast(result)->is_dictionary_map());
set(index, result);
isolate->counters()->normalized_maps()->Increment();
@@ -3343,6 +3345,7 @@
current_heap->isolate()->context()->global_context()->
normalized_map_cache()->Get(this, mode);
if (!maybe_map->To(&new_map)) return maybe_map;
+ ASSERT(new_map->is_dictionary_map());
// We have now successfully allocated all the necessary objects.
// Changes can now be made with the guarantee that all of them take
effect.
@@ -4512,6 +4515,7 @@
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ ASSERT(new_map->is_dictionary_map());
set_map(new_map);
// When running crankshaft, changing the map is not enough. We
@@ -4873,6 +4877,7 @@
result->set_code_cache(code_cache());
result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
+ result->set_dictionary_map(true);
#ifdef DEBUG
if (FLAG_verify_heap && result->is_shared()) {
@@ -7330,7 +7335,8 @@
bit_field2() == other->bit_field2() &&
static_cast<uint32_t>(bit_field3()) ==
LastAddedBits::update(
- IsShared::update(other->bit_field3(), true),
+ IsShared::update(DictionaryMap::update(other->bit_field3(),
true),
+ true),
kNoneAdded);
}
@@ -12573,6 +12579,7 @@
Map* new_map;
MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ new_map->set_dictionary_map(false);
if (instance_descriptor_length == 0) {
ASSERT_LE(unused_property_fields, inobject_props);
=======================================
--- /trunk/src/objects.h Wed Aug 1 04:14:42 2012
+++ /trunk/src/objects.h Wed Aug 8 07:43:45 2012
@@ -4684,7 +4684,8 @@
class IsShared: public BitField<bool, 0, 1> {};
class FunctionWithPrototype: public BitField<bool, 1, 1> {};
- class LastAddedBits: public BitField<int, 2, 11> {};
+ class DictionaryMap: public BitField<bool, 2, 1> {};
+ class LastAddedBits: public BitField<int, 3, 11> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -4830,6 +4831,13 @@
inline void set_is_shared(bool value);
inline bool is_shared();
+ // Tells whether the map is used for JSObjects in dictionary mode (ie
+ // normalized objects, ie objects for which HasFastProperties returns
false).
+ // A map can never be used for both dictionary mode and fast mode
JSObjects.
+ // False by default and for HeapObjects that are not JSObjects.
+ inline void set_dictionary_map(bool value);
+ inline bool is_dictionary_map();
+
// Tells whether the instance needs security checks when accessing its
// properties.
inline void set_is_access_check_needed(bool access_check_needed);
@@ -5150,6 +5158,7 @@
// Bit positions for bit field 3
static const int kIsShared = 0;
static const int kFunctionWithPrototype = 1;
+ static const int kDictionaryMap = 2;
typedef FixedBodyDescriptor<kPointerFieldsBeginOffset,
kPointerFieldsEndOffset,
=======================================
--- /trunk/src/stub-cache.h Thu Jul 5 01:22:44 2012
+++ /trunk/src/stub-cache.h Wed Aug 8 07:43:45 2012
@@ -554,6 +554,15 @@
Handle<String> name,
Label* miss);
+ void GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo> callback,
+ Handle<String> name,
+ Label* miss);
+
void GenerateLoadConstant(Handle<JSObject> object,
Handle<JSObject> holder,
Register receiver,
=======================================
--- /trunk/src/type-info.cc Wed Jun 27 04:12:38 2012
+++ /trunk/src/type-info.cc Wed Aug 8 07:43:45 2012
@@ -95,11 +95,12 @@
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- return code->is_keyed_load_stub() &&
+ bool preliminary_checks = code->is_keyed_load_stub() &&
code->ic_state() == MONOMORPHIC &&
- Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL &&
- code->FindFirstMap() != NULL &&
- !CanRetainOtherContext(code->FindFirstMap(), *global_context_);
+ Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
+ if (!preliminary_checks) return false;
+ Map* map = code->FindFirstMap();
+ return map != NULL && !CanRetainOtherContext(map, *global_context_);
}
return false;
}
@@ -126,12 +127,14 @@
bool allow_growth =
Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
ALLOW_JSARRAY_GROWTH;
- return code->is_keyed_store_stub() &&
+ bool preliminary_checks =
+ code->is_keyed_store_stub() &&
!allow_growth &&
code->ic_state() == MONOMORPHIC &&
- Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL &&
- code->FindFirstMap() != NULL &&
- !CanRetainOtherContext(code->FindFirstMap(), *global_context_);
+ Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
+ if (!preliminary_checks) return false;
+ Map* map = code->FindFirstMap();
+ return map != NULL && !CanRetainOtherContext(map, *global_context_);
}
return false;
}
=======================================
--- /trunk/src/version.cc Fri Aug 3 03:44:23 2012
+++ /trunk/src/version.cc Wed Aug 8 07:43:45 2012
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 12
#define BUILD_NUMBER 19
-#define PATCH_LEVEL 1
+#define PATCH_LEVEL 2
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
=======================================
--- /trunk/src/x64/stub-cache-x64.cc Thu Jul 5 01:22:44 2012
+++ /trunk/src/x64/stub-cache-x64.cc Wed Aug 8 07:43:45 2012
@@ -1027,6 +1027,43 @@
GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
__ ret(0);
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ __ movq(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ scratch2,
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, scratch2 contains the
+ // index into the dictionary. Check that the value is the callback.
+ Register index = scratch2;
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ movq(scratch3,
+ Operand(dictionary, index, times_8, kValueOffset -
kHeapObjectTag));
+ __ movq(scratch2, callback, RelocInfo::EMBEDDED_OBJECT);
+ __ cmpq(scratch3, scratch2);
+ __ j(not_equal, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1046,6 +1083,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Insert additional parameters into the stack frame above return
address.
ASSERT(!scratch2.is(reg));
__ pop(scratch2); // Get return address to place it below.
=======================================
--- /trunk/test/cctest/test-api.cc Tue Jul 24 00:59:48 2012
+++ /trunk/test/cctest/test-api.cc Wed Aug 8 07:43:45 2012
@@ -14731,6 +14731,22 @@
const AccessorInfo& info) {
info.This()->Set(v8_str("y"), v8_num(23));
}
+
+
+Handle<Value> FooGetInterceptor(Local<String> name,
+ const AccessorInfo& info) {
+ if (!name->Equals(v8_str("foo"))) return Handle<Value>();
+ return v8_num(42);
+}
+
+
+Handle<Value> FooSetInterceptor(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info) {
+ if (!name->Equals(v8_str("foo"))) return Handle<Value>();
+ info.This()->Set(v8_str("y"), v8_num(23));
+ return v8_num(23);
+}
TEST(SetterOnConstructorPrototype) {
@@ -16969,26 +16985,61 @@
}
-THREADED_TEST(Regress137002a) {
- i::FLAG_allow_natives_syntax = true;
- v8::HandleScope scope;
+static void Helper137002(bool do_store,
+ bool polymorphic,
+ bool remove_accessor,
+ bool interceptor) {
LocalContext context;
Local<ObjectTemplate> templ = ObjectTemplate::New();
- templ->SetAccessor(v8_str("foo"),
- GetterWhichReturns42,
- SetterWhichSetsYOnThisTo23);
+ if (interceptor) {
+ templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
+ } else {
+ templ->SetAccessor(v8_str("foo"),
+ GetterWhichReturns42,
+ SetterWhichSetsYOnThisTo23);
+ }
context->Global()->Set(v8_str("obj"), templ->NewInstance());
// Turn monomorphic on slow object with native accessor, then turn
// polymorphic, finally optimize to create negative lookup and fail.
- CompileRun("function f(x) { return x.foo; }"
- "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
- "obj.__proto__ = null;"
- "f(obj); f(obj); f({});"
- "%OptimizeFunctionOnNextCall(f);"
- "var result = f(obj);");
- CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
+ CompileRun(do_store ?
+ "function f(x) { x.foo = void 0; }" :
+ "function f(x) { return x.foo; }");
+ CompileRun("obj.y = void 0;");
+ if (!interceptor) {
+ CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
+ }
+ CompileRun("obj.__proto__ = null;"
+ "f(obj); f(obj); f(obj);");
+ if (polymorphic) {
+ CompileRun("f({});");
+ }
+ CompileRun("obj.y = void 0;"
+ "%OptimizeFunctionOnNextCall(f);");
+ if (remove_accessor) {
+ CompileRun("delete obj.foo;");
+ }
+ CompileRun("var result = f(obj);");
+ if (do_store) {
+ CompileRun("result = obj.y;");
+ }
+ if (remove_accessor && !interceptor) {
+ CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
+ } else {
+ CHECK_EQ(do_store ? 23 : 42,
+ context->Global()->Get(v8_str("result"))->Int32Value());
+ }
}
+
+
+THREADED_TEST(Regress137002a) {
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_compilation_cache = false;
+ v8::HandleScope scope;
+ for (int i = 0; i < 16; i++) {
+ Helper137002(i & 8, i & 4, i & 2, i & 1);
+ }
+}
THREADED_TEST(Regress137002b) {
@@ -17003,12 +17054,48 @@
// Turn monomorphic on slow object with native accessor, then just
// delete the property and fail.
- CompileRun("function f(x) { return x.foo; }"
- "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
+ CompileRun("function load(x) { return x.foo; }"
+ "function store(x) { x.foo = void 0; }"
+ "function keyed_load(x, key) { return x[key]; }"
+ // Second version of function has a different source (add
void 0)
+ // so that it does not share code with the first version.
This
+ // ensures that the ICs are monomorphic.
+ "function load2(x) { void 0; return x.foo; }"
+ "function store2(x) { void 0; x.foo = void 0; }"
+ "function keyed_load2(x, key) { void 0; return x[key]; }"
+
"obj.__proto__ = null;"
- "f(obj); f(obj); delete obj.foo;"
- "var result = f(obj);");
- CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
+ "var subobj = {};"
+ "subobj.__proto__ = obj;"
+ "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
+
+ // Make the ICs monomorphic.
+ "load(obj); load(obj);"
+ "load2(subobj); load2(subobj);"
+ "store(obj);"
+ "store2(subobj);"
+ "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
+ "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
+
+ // Delete the accessor. It better not be called any more now.
+ "delete obj.foo;"
+ "obj.y = void 0;"
+ "subobj.y = void 0;"
+
+ "var load_result = load(obj);"
+ "var load_result2 = load2(subobj);"
+ "var keyed_load_result = keyed_load(obj, 'foo');"
+ "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
+ "store(obj);"
+ "store2(subobj);"
+ "var y_from_obj = obj.y;"
+ "var y_from_subobj = subobj.y;");
+ CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
+ CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
+
CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
+
CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
+ CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
+ CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev