Revision: 12264
Author:   [email protected]
Date:     Mon Aug  6 07:25:19 2012
Log: Improve load IC so it can call a native accessor even if the holder is
in dictionary mode.  Add a flag to all maps to indicate whether they are
used for dictionary (normalized) objects or fast mode objects.
Review URL: https://chromiumcodereview.appspot.com/10831153
http://code.google.com/p/v8/source/detail?r=12264

Modified:
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/type-info.cc
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 25 08:26:16 2012 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Aug 6 07:25:19 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);
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Mon Jul 23 09:18:25 2012
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Aug  6 07:25:19 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 =
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Aug  6 06:49:13 2012
+++ /branches/bleeding_edge/src/heap.cc Mon Aug  6 07:25:19 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);
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6 07:25:19 2012
@@ -1743,6 +1743,10 @@
           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() &&
                PrototypeChainCanNeverResolve(map, name)) {
       negative_lookups.Add(types->at(i), zone);
     }
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Mon Aug  6 07:25:19 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 {
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 4 04:40:51 2012 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 6 07:25:19 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.
=======================================
--- /branches/bleeding_edge/src/ic.cc   Wed Aug  1 05:35:33 2012
+++ /branches/bleeding_edge/src/ic.cc   Mon Aug  6 07:25:19 2012
@@ -989,7 +989,6 @@
         if (callback->IsAccessorInfo()) {
           Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
           if (v8::ToCData<Address>(info->getter()) == 0) return;
-          if (!holder->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 (!holder->HasFastProperties()) return;
           code = isolate()->stub_cache()->ComputeLoadViaGetter(
               name, receiver, holder, Handle<JSFunction>::cast(getter));
         } else {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects-inl.h   Mon Aug  6 07:25:19 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() {
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects.cc      Mon Aug  6 07:25:19 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);
 }

@@ -12572,6 +12578,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);
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects.h       Mon Aug  6 07:25:19 2012
@@ -4699,7 +4699,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
@@ -4845,6 +4846,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);
@@ -5165,6 +5173,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,
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Wed Jul  4 04:40:51 2012
+++ /branches/bleeding_edge/src/stub-cache.h    Mon Aug  6 07:25:19 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,
=======================================
--- /branches/bleeding_edge/src/type-info.cc    Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/type-info.cc    Mon Aug  6 07:25:19 2012
@@ -100,11 +100,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;
 }
@@ -131,12 +132,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;
 }
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 4 04:40:51 2012 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Aug 6 07:25:19 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.
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Mon Aug  6 00:55:05 2012
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Mon Aug  6 07:25:19 2012
@@ -16973,9 +16973,9 @@
 }


-THREADED_TEST(Regress137002a) {
-  i::FLAG_allow_natives_syntax = true;
-  v8::HandleScope scope;
+static void Helper137002(bool do_store,
+                         bool polymorphic,
+                         bool remove_accessor) {
   LocalContext context;
   Local<ObjectTemplate> templ = ObjectTemplate::New();
   templ->SetAccessor(v8_str("foo"),
@@ -16985,13 +16985,46 @@

   // 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; }"
+  CompileRun(do_store ?
+             "function f(x) { x.foo = void 0; }" :
+             "function f(x) { return x.foo; }");
+  CompileRun("obj.y = void 0;"
              "%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());
+             "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) {
+    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;
+  Helper137002(false, false, false);
+  Helper137002(false, false, true);
+  Helper137002(false, true, false);
+  Helper137002(false, true, true);
+  Helper137002(true, false, false);
+  Helper137002(true, false, true);
+  Helper137002(true, true, false);
+  Helper137002(true, true, true);
 }


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to