Revision: 10827
Author:   [email protected]
Date:     Fri Feb 24 06:34:01 2012
Log:      Fix redefining of attributes on aliased arguments.

This allows elements of the non-strict arguments object to be redefined
with custom attributes and still maintain an alias into the context.
Such a slow alias is maintained by placing a special marker into the
dictionary backing store of the arguments object.

[email protected]
BUG=v8:1772
TEST=test262,mjsunit/object-define-property

Review URL: https://chromiumcodereview.appspot.com/9460004
http://code.google.com/p/v8/source/detail?r=10827

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/elements.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/objects-debug.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects-printer.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/test/mjsunit/object-define-property.js
 /branches/bleeding_edge/test/test262/test262.status

=======================================
--- /branches/bleeding_edge/include/v8.h        Mon Feb 20 05:48:24 2012
+++ /branches/bleeding_edge/include/v8.h        Fri Feb 24 06:34:01 2012
@@ -3850,7 +3850,7 @@
   static const int kFullStringRepresentationMask = 0x07;
   static const int kExternalTwoByteRepresentationTag = 0x02;

-  static const int kJSObjectType = 0xa8;
+  static const int kJSObjectType = 0xa9;
   static const int kFirstNonstringType = 0x80;
   static const int kForeignType = 0x85;

=======================================
--- /branches/bleeding_edge/src/elements.cc     Mon Feb 20 02:17:25 2012
+++ /branches/bleeding_edge/src/elements.cc     Fri Feb 24 06:34:01 2012
@@ -705,10 +705,20 @@
     } else {
       // Object is not mapped, defer to the arguments.
       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
-      return ElementsAccessor::ForArray(arguments)->Get(arguments,
-                                                        key,
-                                                        obj,
-                                                        receiver);
+ MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
+          arguments, key, obj, receiver);
+      Object* result;
+      if (!maybe_result->ToObject(&result)) return maybe_result;
+ // Elements of the arguments object in slow mode might be slow aliases.
+      if (result->IsAliasedArgumentsEntry()) {
+        AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
+        Context* context = Context::cast(parameter_map->get(0));
+        int context_index = entry->aliased_context_slot();
+        ASSERT(!context->get(context_index)->IsTheHole());
+        return context->get(context_index);
+      } else {
+        return result;
+      }
     }
   }

=======================================
--- /branches/bleeding_edge/src/heap.cc Thu Feb 23 04:11:24 2012
+++ /branches/bleeding_edge/src/heap.cc Fri Feb 24 06:34:01 2012
@@ -1949,6 +1949,16 @@
                                 SKIP_WRITE_BARRIER);
   return info;
 }
+
+
+MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
+  AliasedArgumentsEntry* entry;
+ { MaybeObject* maybe_result = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
+    if (!maybe_result->To(&entry)) return maybe_result;
+  }
+  entry->set_aliased_context_slot(aliased_context_slot);
+  return entry;
+}


 const Heap::StringTypeTable Heap::string_type_table[] = {
=======================================
--- /branches/bleeding_edge/src/heap.h  Thu Feb 23 04:11:24 2012
+++ /branches/bleeding_edge/src/heap.h  Fri Feb 24 06:34:01 2012
@@ -641,6 +641,9 @@
   // Allocates an empty TypeFeedbackInfo.
   MUST_USE_RESULT MaybeObject* AllocateTypeFeedbackInfo();

+  // Allocates an AliasedArgumentsEntry.
+  MUST_USE_RESULT MaybeObject* AllocateAliasedArgumentsEntry(int slot);
+
   // Clear the Instanceof cache (used when a prototype changes).
   inline void ClearInstanceofCache();

=======================================
--- /branches/bleeding_edge/src/objects-debug.cc        Mon Feb 20 04:57:23 2012
+++ /branches/bleeding_edge/src/objects-debug.cc        Fri Feb 24 06:34:01 2012
@@ -331,6 +331,11 @@
   VerifyObjectField(kIcWithTypeinfoCountOffset);
   VerifyHeapPointer(type_feedback_cells());
 }
+
+
+void AliasedArgumentsEntry::AliasedArgumentsEntryVerify() {
+  VerifySmiField(kAliasedContextSlot);
+}


 void FixedArray::FixedArrayVerify() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Thu Feb 23 01:12:57 2012
+++ /branches/bleeding_edge/src/objects-inl.h   Fri Feb 24 06:34:01 2012
@@ -4806,6 +4806,9 @@
           kTypeFeedbackCellsOffset)


+SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot, kAliasedContextSlot)
+
+
 Relocatable::Relocatable(Isolate* isolate) {
   ASSERT(isolate == Isolate::Current());
   isolate_ = isolate;
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc      Mon Feb 20 04:57:23 2012
+++ /branches/bleeding_edge/src/objects-printer.cc      Fri Feb 24 06:34:01 2012
@@ -561,6 +561,12 @@
   PrintF(out, "\n - type_feedback_cells: ");
   type_feedback_cells()->FixedArrayPrint(out);
 }
+
+
+void AliasedArgumentsEntry::AliasedArgumentsEntryPrint(FILE* out) {
+  HeapObject::PrintHeader(out, "AliasedArgumentsEntry");
+  PrintF(out, "\n - aliased_context_slot: %d", aliased_context_slot());
+}


 void FixedArray::FixedArrayPrint(FILE* out) {
=======================================
--- /branches/bleeding_edge/src/objects.cc      Fri Feb 24 05:04:16 2012
+++ /branches/bleeding_edge/src/objects.cc      Fri Feb 24 06:34:01 2012
@@ -9559,19 +9559,31 @@
       // value is being defined we skip attribute checks completely.
       if (set_mode == DEFINE_PROPERTY) {
         details = PropertyDetails(attributes, NORMAL, details.index());
-        dictionary->ValueAtPut(entry, value);
         dictionary->DetailsAtPut(entry, details);
-      } else if (!details.IsReadOnly() || element->IsTheHole()) {
-        dictionary->ValueAtPut(entry, value);
-      } else if (strict_mode == kStrictMode) {
-        Handle<Object> holder(this);
- Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
-        Handle<Object> args[2] = { number, holder };
-        Handle<Object> error =
-            isolate->factory()->NewTypeError("strict_read_only_property",
-                                             HandleVector(args, 2));
-        return isolate->Throw(*error);
-      }
+      } else if (details.IsReadOnly() && !element->IsTheHole()) {
+        if (strict_mode == kNonStrictMode) {
+          return isolate->heap()->undefined_value();
+        } else {
+          Handle<Object> holder(this);
+ Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
+          Handle<Object> args[2] = { number, holder };
+          Handle<Object> error =
+              isolate->factory()->NewTypeError("strict_read_only_property",
+                                               HandleVector(args, 2));
+          return isolate->Throw(*error);
+        }
+      }
+ // Elements of the arguments object in slow mode might be slow aliases.
+      if (is_arguments && element->IsAliasedArgumentsEntry()) {
+ AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
+        Context* context = Context::cast(elements->get(0));
+        int context_index = entry->aliased_context_slot();
+        ASSERT(!context->get(context_index)->IsTheHole());
+        context->set(context_index, value);
+        // For elements that are still writable we keep slow aliasing.
+        if (!details.IsReadOnly()) value = element;
+      }
+      dictionary->ValueAtPut(entry, value);
     }
   } else {
     // Index not already used. Look for an accessor in the prototype chain.
@@ -9927,17 +9939,23 @@
         int context_index = Smi::cast(probe)->value();
         ASSERT(!context->get(context_index)->IsTheHole());
         context->set(context_index, value);
-        return value;
-      } else {
-        // Object is not mapped, defer to the arguments.
-        FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
-        if (arguments->IsDictionary()) {
-          return SetDictionaryElement(index, value, attr, strict_mode,
-                                      check_prototype, set_mode);
-        } else {
- return SetFastElement(index, value, strict_mode, check_prototype); + // Redefining attributes of an aliased element destroys fast aliasing.
+        if (set_mode == SET_PROPERTY || attr == NONE) return value;
+        parameter_map->set_the_hole(index + 2);
+ // For elements that are still writable we re-establish slow aliasing.
+        if ((attr & READ_ONLY) == 0) {
+          MaybeObject* maybe_entry =
+ isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
+          if (!maybe_entry->ToObject(&value)) return maybe_entry;
         }
       }
+      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+      if (arguments->IsDictionary()) {
+        return SetDictionaryElement(index, value, attr, strict_mode,
+                                    check_prototype, set_mode);
+      } else {
+        return SetFastElement(index, value, strict_mode, check_prototype);
+      }
     }
   }
   // All possible cases have been handled above. Add a return to avoid the
=======================================
--- /branches/bleeding_edge/src/objects.h       Thu Feb 23 03:43:07 2012
+++ /branches/bleeding_edge/src/objects.h       Fri Feb 24 06:34:01 2012
@@ -440,7 +440,8 @@
V(SCRIPT, Script, script) \ V(CODE_CACHE, CodeCache, code_cache) \ V(POLYMORPHIC_CODE_CACHE, PolymorphicCodeCache, polymorphic_code_cache) \
-  V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info)
+ V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info) \ + V(ALIASED_ARGUMENTS_ENTRY, AliasedArgumentsEntry, aliased_arguments_entry)

 #ifdef ENABLE_DEBUGGER_SUPPORT
#define STRUCT_LIST_DEBUGGER(V) \
@@ -596,6 +597,7 @@
   CODE_CACHE_TYPE,
   POLYMORPHIC_CODE_CACHE_TYPE,
   TYPE_FEEDBACK_INFO_TYPE,
+  ALIASED_ARGUMENTS_ENTRY_TYPE,
// The following two instance types are only used when ENABLE_DEBUGGER_SUPPORT
   // is defined. However as include/v8.h contain some of the instance type
   // constants always having them avoids them getting different numbers
@@ -6435,6 +6437,39 @@
 };


+// Representation of a slow alias as part of a non-strict arguments objects.
+// For fast aliases (if HasNonStrictArgumentsElements()):
+// - the parameter map contains an index into the context
+// - all attributes of the element have default values
+// For slow aliases (if HasDictionaryArgumentsElements()):
+// - the parameter map contains no fast alias mapping (i.e. the hole)
+// - this struct (in the slow backing store) contains an index into the context
+// - all attributes are available as part if the property details
+class AliasedArgumentsEntry: public Struct {
+ public:
+  inline int aliased_context_slot();
+  inline void set_aliased_context_slot(int count);
+
+  static inline AliasedArgumentsEntry* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+  inline void AliasedArgumentsEntryPrint() {
+    AliasedArgumentsEntryPrint(stdout);
+  }
+  void AliasedArgumentsEntryPrint(FILE* out);
+#endif
+#ifdef DEBUG
+  void AliasedArgumentsEntryVerify();
+#endif
+
+  static const int kAliasedContextSlot = HeapObject::kHeaderSize;
+  static const int kSize = kAliasedContextSlot + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(AliasedArgumentsEntry);
+};
+
+
 enum AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
 enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};

=======================================
--- /branches/bleeding_edge/test/mjsunit/object-define-property.js Wed Jun 8 01:13:31 2011 +++ /branches/bleeding_edge/test/mjsunit/object-define-property.js Fri Feb 24 06:34:01 2012
@@ -1054,3 +1054,24 @@
   Object.defineProperty(o, i, {value: i, enumerable: false});
 }
 assertEquals(999, o[999]);
+
+
+// Regression test: Bizzare behavior on non-strict arguments object.
+(function test(arg0) {
+  // Here arguments[0] is a fast alias on arg0.
+  Object.defineProperty(arguments, "0", {
+    value:1,
+    enumerable:false
+  });
+  // Here arguments[0] is a slow alias on arg0.
+  Object.defineProperty(arguments, "0", {
+    value:2,
+    writable:false
+  });
+  // Here arguments[0] is no alias at all.
+  Object.defineProperty(arguments, "0", {
+    value:3
+  });
+  assertEquals(2, arg0);
+  assertEquals(3, arguments[0]);
+})(0);
=======================================
--- /branches/bleeding_edge/test/test262/test262.status Thu Feb 23 03:43:07 2012 +++ /branches/bleeding_edge/test/test262/test262.status Fri Feb 24 06:34:01 2012
@@ -42,19 +42,6 @@
 15.2.3.6-4-415: FAIL
 15.2.3.6-4-420: FAIL

-# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1772
-15.2.3.6-4-292-1: FAIL
-15.2.3.6-4-293-2: FAIL
-15.2.3.6-4-293-3: FAIL
-15.2.3.6-4-294-1: FAIL
-15.2.3.6-4-295-1: FAIL
-15.2.3.6-4-296-1: FAIL
-15.2.3.7-6-a-281: FAIL
-15.2.3.7-6-a-282: FAIL
-15.2.3.7-6-a-283: FAIL
-15.2.3.7-6-a-284: FAIL
-15.2.3.7-6-a-285: FAIL
-
 ##################### DELIBERATE INCOMPATIBILITIES #####################

 # We deliberately treat arguments to parseInt() with a leading zero as

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

Reply via email to