Author: [email protected]
Date: Thu Mar 19 15:21:34 2009
New Revision: 1555

Modified:
    trunk/include/v8.h
    trunk/src/api.cc
    trunk/src/factory.h
    trunk/src/handles.cc
    trunk/src/handles.h
    trunk/src/heap.cc
    trunk/src/heap.h
    trunk/src/objects-inl.h
    trunk/src/objects.cc
    trunk/src/objects.h
    trunk/src/spaces.h
    trunk/src/stub-cache.cc
    trunk/test/cctest/test-api.cc

Log:
Push revisions 1527, 1539, 1540, 1541, 1550, 1551 from bleeding_edge to  
trunk.

Modified: trunk/include/v8.h
==============================================================================
--- trunk/include/v8.h  (original)
+++ trunk/include/v8.h  Thu Mar 19 15:21:34 2009
@@ -1075,6 +1075,28 @@
     * access check info, the object cannot be accessed by anyone.
     */
    void TurnOnAccessCheck();
+
+  /**
+   * Returns the identity hash for this object. The current implemenation  
uses
+   * a hidden property on the object to store the identity hash.
+   */
+  int GetIdentityHash();
+
+  /**
+   * Access hidden properties on JavaScript objects. These properties are
+   * hidden from the executing JavaScript and only accessible through the  
V8
+   * C++ API. Hidden properties introduced by V8 internally (for example  
the
+   * identity hash) are prefixed with "v8::".
+   */
+  bool SetHiddenValue(Handle<String> key, Handle<Value> value);
+  Local<Value> GetHiddenValue(Handle<String> key);
+  bool DeleteHiddenValue(Handle<String> key);
+
+  /**
+   * Clone this object with a fast but shallow copy.  Values will point
+   * to the same values as the original object.
+   */
+  Local<Object> Clone();

    static Local<Object> New();
    static Object* Cast(Value* obj);

Modified: trunk/src/api.cc
==============================================================================
--- trunk/src/api.cc    (original)
+++ trunk/src/api.cc    Thu Mar 19 15:21:34 2009
@@ -1919,6 +1919,88 @@
  }


+Local<v8::Object> v8::Object::Clone() {
+  ON_BAILOUT("v8::Object::Clone()", return Local<Object>());
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::JSObject> result = i::Copy(self);
+  has_pending_exception = result.is_null();
+  EXCEPTION_BAILOUT_CHECK(Local<Object>());
+  return Utils::ToLocal(result);
+}
+
+
+int v8::Object::GetIdentityHash() {
+  ON_BAILOUT("v8::Object::GetIdentityHash()", return 0);
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
+  i::Handle<i::Object> hash_symbol = i::Factory::identity_hash_symbol();
+  i::Handle<i::Object> hash = i::GetProperty(hidden_props, hash_symbol);
+  int hash_value;
+  if (hash->IsSmi()) {
+    hash_value = i::Smi::cast(*hash)->value();
+  } else {
+    hash_value = random() & i::Smi::kMaxValue;  // Limit range to fit a  
smi.
+    i::SetProperty(hidden_props,
+                   hash_symbol,
+                   i::Handle<i::Object>(i::Smi::FromInt(hash_value)),
+                   static_cast<PropertyAttributes>(None));
+  }
+  return hash_value;
+}
+
+
+bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
+                                v8::Handle<v8::Value> value) {
+  ON_BAILOUT("v8::Object::SetHiddenValue()", return false);
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj = i::SetProperty(
+      hidden_props,
+      key_obj,
+      value_obj,
+      static_cast<PropertyAttributes>(None));
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(false);
+  return true;
+}
+
+
+v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String>  
key) {
+  ON_BAILOUT("v8::Object::GetHiddenValue()", return Local<v8::Value>());
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
+  if (hidden_props->IsUndefined()) {
+    return v8::Local<v8::Value>();
+  }
+  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = i::GetProperty(hidden_props, key_obj);
+  has_pending_exception = result.is_null();
+  EXCEPTION_BAILOUT_CHECK(v8::Local<v8::Value>());
+  if (result->IsUndefined()) {
+    return v8::Local<v8::Value>();
+  }
+  return Utils::ToLocal(result);
+}
+
+
+bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
+  ON_BAILOUT("v8::DeleteHiddenValue()", return false);
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::JSObject> hidden_props(
+      i::JSObject::cast(*i::GetHiddenProperties(self, false)));
+  if (hidden_props->IsUndefined()) {
+    return false;
+  }
+  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  return i::DeleteProperty(hidden_props, key_obj)->IsTrue();
+}
+
+
  Local<v8::Object> Function::NewInstance() const {
    return NewInstance(0, NULL);
  }
@@ -2200,7 +2282,7 @@


  const char* v8::V8::GetVersion() {
-  return "1.1.1.2";
+  return "1.1.1.3";
  }



Modified: trunk/src/factory.h
==============================================================================
--- trunk/src/factory.h (original)
+++ trunk/src/factory.h Thu Mar 19 15:21:34 2009
@@ -302,6 +302,10 @@
    SYMBOL_LIST(SYMBOL_ACCESSOR)
  #undef SYMBOL_ACCESSOR

+  static Handle<String> hidden_symbol() {
+    return Handle<String>(&Heap::hidden_symbol_);
+  }
+
    static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String>  
name);

    static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,

Modified: trunk/src/handles.cc
==============================================================================
--- trunk/src/handles.cc        (original)
+++ trunk/src/handles.cc        Thu Mar 19 15:21:34 2009
@@ -52,44 +52,39 @@
  }


-void** HandleScope::CreateHandle(void* value) {
+void** HandleScope::Extend() {
    void** result = current_.next;
-  if (result == current_.limit) {
-    // Make sure there's at least one scope on the stack and that the
-    // top of the scope stack isn't a barrier.
-    if (current_.extensions < 0) {
-      Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
-                              "Cannot create a handle without a  
HandleScope");
-      return NULL;
-    }
-    HandleScopeImplementer* impl = HandleScopeImplementer::instance();
-    // If there's more room in the last block, we use that. This is used
-    // for fast creation of scopes after scope barriers.
-    if (!impl->Blocks()->is_empty()) {
-      void** limit = &impl->Blocks()->last()[kHandleBlockSize];
-      if (current_.limit != limit) {
-        current_.limit = limit;
-      }
-    }

-    // If we still haven't found a slot for the handle, we extend the
-    // current handle scope by allocating a new handle block.
-    if (result == current_.limit) {
-      // If there's a spare block, use it for growing the current scope.
-      result = impl->GetSpareOrNewBlock();
-      // Add the extension to the global list of blocks, but count the
-      // extension as part of the current scope.
-      impl->Blocks()->Add(result);
-      current_.extensions++;
-      current_.limit = &result[kHandleBlockSize];
+  ASSERT(result == current_.limit);
+  // Make sure there's at least one scope on the stack and that the
+  // top of the scope stack isn't a barrier.
+  if (current_.extensions < 0) {
+    Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
+                            "Cannot create a handle without a  
HandleScope");
+    return NULL;
+  }
+  HandleScopeImplementer* impl = HandleScopeImplementer::instance();
+  // If there's more room in the last block, we use that. This is used
+  // for fast creation of scopes after scope barriers.
+  if (!impl->Blocks()->is_empty()) {
+    void** limit = &impl->Blocks()->last()[kHandleBlockSize];
+    if (current_.limit != limit) {
+      current_.limit = limit;
      }
    }

-  // Update the current next field, set the value in the created
-  // handle, and return the result.
-  ASSERT(result < current_.limit);
-  current_.next = result + 1;
-  *result = value;
+  // If we still haven't found a slot for the handle, we extend the
+  // current handle scope by allocating a new handle block.
+  if (result == current_.limit) {
+    // If there's a spare block, use it for growing the current scope.
+    result = impl->GetSpareOrNewBlock();
+    // Add the extension to the global list of blocks, but count the
+    // extension as part of the current scope.
+    impl->Blocks()->Add(result);
+    current_.extensions++;
+    current_.limit = &result[kHandleBlockSize];
+  }
+
    return result;
  }

@@ -263,6 +258,12 @@
  Handle<Object> GetPrototype(Handle<Object> obj) {
    Handle<Object> result(obj->GetPrototype());
    return result;
+}
+
+
+Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
+                                   bool create_if_needed) {
+  CALL_HEAP_FUNCTION(obj->GetHiddenProperties(create_if_needed), Object);
  }



Modified: trunk/src/handles.h
==============================================================================
--- trunk/src/handles.h (original)
+++ trunk/src/handles.h Thu Mar 19 15:21:34 2009
@@ -118,7 +118,16 @@
    static int NumberOfHandles();

    // Creates a new handle with the given value.
-  static void** CreateHandle(void* value);
+  static inline void** CreateHandle(void* value) {
+    void** result = current_.next;
+    if (result == current_.limit) result = Extend();
+    // Update the current next field, set the value in the created
+    // handle, and return the result.
+    ASSERT(result < current_.limit);
+    current_.next = result + 1;
+    *result = value;
+    return result;
+  }

   private:
    // Prevent heap allocation or illegal handle scopes.
@@ -150,6 +159,9 @@
  #endif
    }

+  // Extend the handle scope making room for more handles.
+  static void** Extend();
+
    // Deallocates any extensions used by the current scope.
    static void DeleteExtensions();

@@ -210,6 +222,8 @@
                                            PropertyAttributes* attributes);

  Handle<Object> GetPrototype(Handle<Object> obj);
+
+Handle<Object> GetHiddenProperties(Handle<JSObject> obj, bool  
create_if_needed);

  Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
  Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> prop);

Modified: trunk/src/heap.cc
==============================================================================
--- trunk/src/heap.cc   (original)
+++ trunk/src/heap.cc   Thu Mar 19 15:21:34 2009
@@ -57,6 +57,8 @@
    SYMBOL_LIST(SYMBOL_ALLOCATION)
  #undef SYMBOL_ALLOCATION

+String* Heap::hidden_symbol_;
+
  NewSpace Heap::new_space_;
  OldSpace* Heap::old_pointer_space_ = NULL;
  OldSpace* Heap::old_data_space_ = NULL;
@@ -1206,6 +1208,16 @@
    SYMBOL_LIST(SYMBOL_INITIALIZE)
  #undef SYMBOL_INITIALIZE

+  // Allocate the hidden symbol which is used to identify the hidden  
properties
+  // in JSObjects. The hash code has a special value so that it will not  
match
+  // the empty string when searching for the property. It cannot be part  
of the
+  // SYMBOL_LIST because it needs to be allocated manually with the special
+  // hash code in place. The hash code for the hidden_symbol is zero to  
ensure
+  // that it will always be at the first entry in property descriptors.
+  obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask);
+  if (obj->IsFailure()) return false;
+  hidden_symbol_ = String::cast(obj);
+
    // Allocate the proxy for __proto__.
    obj = AllocateProxy((Address) &Accessors::ObjectPrototype);
    if (obj->IsFailure()) return false;
@@ -2650,6 +2662,7 @@
    v->VisitPointer(bit_cast<Object**, String**>(&name##_));
    SYMBOL_LIST(SYMBOL_ITERATE)
  #undef SYMBOL_ITERATE
+  v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
    SYNCHRONIZE_TAG("symbol");

    Bootstrapper::Iterate(v);

Modified: trunk/src/heap.h
==============================================================================
--- trunk/src/heap.h    (original)
+++ trunk/src/heap.h    Thu Mar 19 15:21:34 2009
@@ -195,7 +195,8 @@
    V(space_symbol, " ")                                                   \
    V(exec_symbol, "exec")                                                 \
    V(zero_symbol, "0")                                                    \
-  V(global_eval_symbol, "GlobalEval")
+  V(global_eval_symbol, "GlobalEval")                                    \
+  V(identity_hash_symbol, "v8::IdentityHash")


  // Forward declaration of the GCTracer class.
@@ -645,6 +646,10 @@
    SYMBOL_LIST(SYMBOL_ACCESSOR)
  #undef SYMBOL_ACCESSOR

+  // The hidden_symbol is special because it is the empty string, but does
+  // not match the empty string.
+  static String* hidden_symbol() { return hidden_symbol_; }
+
    // Iterates over all roots in the heap.
    static void IterateRoots(ObjectVisitor* v);
    // Iterates over all strong roots in the heap.
@@ -887,6 +892,10 @@
  #define SYMBOL_DECLARATION(name, str) static String* name##_;
    SYMBOL_LIST(SYMBOL_DECLARATION)
  #undef SYMBOL_DECLARATION
+
+  // The special hidden symbol which is an empty string, but does not match
+  // any string when looked up in properties.
+  static String* hidden_symbol_;

    // GC callback function, called before and after mark-compact GC.
    // Allocations in the callback function are disallowed.

Modified: trunk/src/objects-inl.h
==============================================================================
--- trunk/src/objects-inl.h     (original)
+++ trunk/src/objects-inl.h     Thu Mar 19 15:21:34 2009
@@ -2438,10 +2438,15 @@


  uint32_t StringHasher::GetHash() {
+  // Get the calculated raw hash value and do some more bit ops to  
distribute
+  // the hash further. Ensure that we never return zero as the hash value.
    uint32_t result = raw_running_hash_;
    result += (result << 3);
    result ^= (result >> 11);
    result += (result << 15);
+  if (result == 0) {
+    result = 27;
+  }
    return result;
  }


Modified: trunk/src/objects.cc
==============================================================================
--- trunk/src/objects.cc        (original)
+++ trunk/src/objects.cc        Thu Mar 19 15:21:34 2009
@@ -3113,8 +3113,12 @@


  int DescriptorArray::LinearSearch(String* name, int len) {
+  uint32_t hash = name->Hash();
    for (int number = 0; number < len; number++) {
-    if (name->Equals(GetKey(number)) && !is_null_descriptor(number)) {
+    String* entry = GetKey(number);
+    if ((entry->Hash() == hash) &&
+        name->Equals(entry) &&
+        !is_null_descriptor(number)) {
        return number;
      }
    }
@@ -4187,7 +4191,7 @@


  uint32_t String::ComputeAndSetHash() {
-  // Should only be call if hash code has not yet been computed.
+  // Should only be called if hash code has not yet been computed.
    ASSERT(!(length_field() & kHashComputedMask));

    // Compute the hash code.
@@ -4199,7 +4203,9 @@

    // Check the hash code is there.
    ASSERT(length_field() & kHashComputedMask);
-  return field >> kHashShift;
+  uint32_t result = field >> kHashShift;
+  ASSERT(result != 0);  // Ensure that the hash value of 0 is never  
computed.
+  return result;
  }


@@ -5081,6 +5087,45 @@
  }


+Object* JSObject::GetHiddenProperties(bool create_if_needed) {
+  String* key = Heap::hidden_symbol();
+  if (this->HasFastProperties()) {
+    // If the object has fast properties, check whether the first slot in  
the
+    // descriptor array matches the hidden symbol. Since the hidden symbols
+    // hash code is zero it will always occupy the first entry if present.
+    DescriptorArray* descriptors = this->map()->instance_descriptors();
+    if (descriptors->number_of_descriptors() > 0) {
+      if (descriptors->GetKey(0) == key) {
+#ifdef DEBUG
+        PropertyDetails details(descriptors->GetDetails(0));
+        ASSERT(details.type() == FIELD);
+#endif  // DEBUG
+        Object* value = descriptors->GetValue(0);
+        return FastPropertyAt(Descriptor::IndexFromValue(value));
+      }
+    }
+  }
+
+  // Only attempt to find the hidden properties in the local object and not
+  // in the prototype chain.
+  if (!this->HasLocalProperty(key)) {
+    // Hidden properties object not found. Allocate a new hidden properties
+    // object if requested. Otherwise return the undefined value.
+    if (create_if_needed) {
+      Object* obj = Heap::AllocateJSObject(
+          Top::context()->global_context()->object_function());
+      if (obj->IsFailure()) {
+        return obj;
+      }
+      return this->SetProperty(key, obj, DONT_ENUM);
+    } else {
+      return Heap::undefined_value();
+    }
+  }
+  return this->GetProperty(key);
+}
+
+
  bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
    // Check access rights if needed.
    if (IsAccessCheckNeeded() &&
@@ -5927,13 +5972,20 @@
  // StringKey simply carries a string object as key.
  class StringKey : public HashTableKey {
   public:
-  explicit StringKey(String* string) : string_(string) { }
+  explicit StringKey(String* string) :
+      string_(string),
+      hash_(StringHash(string)) { }

    bool IsMatch(Object* string) {
+    // We know that all entries in a hash table had their hash keys  
created.
+    // Use that knowledge to have fast failure.
+    if (hash_ != StringHash(string)) {
+      return false;
+    }
      return string_->Equals(String::cast(string));
    }

-  uint32_t Hash() { return StringHash(string_); }
+  uint32_t Hash() { return hash_; }

    HashFunction GetHashFunction() { return StringHash; }

@@ -5946,6 +5998,7 @@
    bool IsStringKey() { return true; }

    String* string_;
+  uint32_t hash_;
  };


@@ -6072,7 +6125,9 @@
                                         
static_cast<unsigned>(string_.length()));
      chars_ = buffer.Length();
      length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
-    return length_field_ >> String::kHashShift;
+    uint32_t result = length_field_ >> String::kHashShift;
+    ASSERT(result != 0);  // Ensure that the hash value of 0 is never  
computed.
+    return result;
    }

    Object* GetObject() {

Modified: trunk/src/objects.h
==============================================================================
--- trunk/src/objects.h (original)
+++ trunk/src/objects.h Thu Mar 19 15:21:34 2009
@@ -1243,6 +1243,11 @@
    // Return the object's prototype (might be Heap::null_value()).
    inline Object* GetPrototype();

+  // Return the object's hidden properties object. If the object has no  
hidden
+  // properties and create_if_needed is true, then a new hidden property  
object
+  // will be allocated. Otherwise the Heap::undefined_value is returned.
+  Object* GetHiddenProperties(bool create_if_needed);
+
    // Tells whether the index'th element is present.
    inline bool HasElement(uint32_t index);
    bool HasElementWithReceiver(JSObject* receiver, uint32_t index);

Modified: trunk/src/spaces.h
==============================================================================
--- trunk/src/spaces.h  (original)
+++ trunk/src/spaces.h  Thu Mar 19 15:21:34 2009
@@ -1481,7 +1481,7 @@
    MapSpaceFreeList free_list_;

    // An array of page start address in a map space.
-  Address page_addresses_[kMaxMapPageIndex];
+  Address page_addresses_[kMaxMapPageIndex + 1];

   public:
    TRACK_MEMORY("MapSpace")

Modified: trunk/src/stub-cache.cc
==============================================================================
--- trunk/src/stub-cache.cc     (original)
+++ trunk/src/stub-cache.cc     Thu Mar 19 15:21:34 2009
@@ -656,9 +656,8 @@
  Object* LoadCallbackProperty(Arguments args) {
    Handle<JSObject> recv = args.at<JSObject>(0);
    AccessorInfo* callback = AccessorInfo::cast(args[1]);
-  v8::AccessorGetter fun =
-      FUNCTION_CAST<v8::AccessorGetter>(
-          v8::ToCData<Address>(callback->getter()));
+  Address getter_address = v8::ToCData<Address>(callback->getter());
+  v8::AccessorGetter fun =  
FUNCTION_CAST<v8::AccessorGetter>(getter_address);
    ASSERT(fun != NULL);
    Handle<String> name = args.at<String>(2);
    Handle<JSObject> holder = args.at<JSObject>(3);
@@ -669,10 +668,9 @@
    // locations of the arguments to this function maybe we don't have
    // to explicitly create the structure but can just pass a pointer
    // into the stack.
-  v8::AccessorInfo info(
-    v8::Utils::ToLocal(recv),
-    v8::Utils::ToLocal(data),
-    v8::Utils::ToLocal(holder));
+  v8::AccessorInfo info(v8::Utils::ToLocal(recv),
+                        v8::Utils::ToLocal(data),
+                        v8::Utils::ToLocal(holder));
    v8::Handle<v8::Value> result;
    {
      // Leaving JavaScript.
@@ -680,30 +678,25 @@
      result = fun(v8::Utils::ToLocal(name), info);
    }
    RETURN_IF_SCHEDULED_EXCEPTION();
-  if (result.IsEmpty()) {
-    return Heap::undefined_value();
-  } else {
-    return *v8::Utils::OpenHandle(*result);
-  }
+  if (result.IsEmpty()) return Heap::undefined_value();
+  return *v8::Utils::OpenHandle(*result);
  }


  Object* StoreCallbackProperty(Arguments args) {
    Handle<JSObject> recv = args.at<JSObject>(0);
    AccessorInfo* callback = AccessorInfo::cast(args[1]);
-  v8::AccessorSetter fun =
-      FUNCTION_CAST<v8::AccessorSetter>(
-          v8::ToCData<Address>(callback->setter()));
+  Address setter_address = v8::ToCData<Address>(callback->setter());
+  v8::AccessorSetter fun =  
FUNCTION_CAST<v8::AccessorSetter>(setter_address);
    ASSERT(fun != NULL);
    Handle<String> name = args.at<String>(2);
    Handle<Object> value = args.at<Object>(3);
    HandleScope scope;
    Handle<Object> data(callback->data());
    LOG(ApiNamedPropertyAccess("store", *recv, *name));
-  v8::AccessorInfo info(
-    v8::Utils::ToLocal(recv),
-    v8::Utils::ToLocal(data),
-    v8::Utils::ToLocal(recv));
+  v8::AccessorInfo info(v8::Utils::ToLocal(recv),
+                        v8::Utils::ToLocal(data),
+                        v8::Utils::ToLocal(recv));
    {
      // Leaving JavaScript.
      VMState state(OTHER);
@@ -715,28 +708,17 @@


  Object* LoadInterceptorProperty(Arguments args) {
-  HandleScope scope;
-  Handle<JSObject> recv = args.at<JSObject>(0);
-  Handle<JSObject> holder = args.at<JSObject>(1);
-  Handle<String> name = args.at<String>(2);
+  JSObject* recv = JSObject::cast(args[0]);
+  JSObject* holder = JSObject::cast(args[1]);
+  String* name = String::cast(args[2]);
    ASSERT(holder->HasNamedInterceptor());
    PropertyAttributes attr = NONE;
-  Handle<Object> result = GetPropertyWithInterceptor(recv, holder, name,  
&attr);
+  Object* result = holder->GetPropertyWithInterceptor(recv, name, &attr);

-  // GetPropertyWithInterceptor already converts a scheduled exception
-  // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION()  
here.
-
-  // Make sure to propagate exceptions.
-  if (result.is_null())  {
-    // Failure::Exception is converted to a null handle in the
-    // handle-based methods such as SetProperty.  We therefore need
-    // to convert null handles back to exceptions.
-    ASSERT(Top::has_pending_exception());
-    return Failure::Exception();
-  }
+  if (result->IsFailure()) return result;

    // If the property is present, return it.
-  if (attr != ABSENT) return *result;
+  if (attr != ABSENT) return result;

    // If the top frame is an internal frame, this is really a call
    // IC. In this case, we simply return the undefined result which
@@ -744,43 +726,38 @@
    // function.
    StackFrameIterator it;
    it.Advance();  // skip exit frame
-  if (it.frame()->is_internal()) return *result;
+  if (it.frame()->is_internal()) return result;

    // If the load is non-contextual, just return the undefined result.
    // Note that both keyed and non-keyed loads may end up here, so we
    // can't use either LoadIC or KeyedLoadIC constructors.
    IC ic(IC::NO_EXTRA_FRAME);
    ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
-  if (!ic.is_contextual()) return *result;
+  if (!ic.is_contextual()) return result;

    // Throw a reference error.
-  Handle<Object> error =
-      Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
-  return Top::Throw(*error);
+  {
+    HandleScope scope;
+    // We cannot use the raw name pointer here since getting the
+    // property might cause a GC.  However, we can get the name from
+    // the stack using the arguments object.
+    Handle<String> name_handle = args.at<String>(2);
+    Handle<Object> error =
+        Factory::NewReferenceError("not_defined",
+                                   HandleVector(&name_handle, 1));
+    return Top::Throw(*error);
+  }
  }


  Object* StoreInterceptorProperty(Arguments args) {
-  HandleScope scope;
-  Handle<JSObject> recv = args.at<JSObject>(0);
-  Handle<String> name = args.at<String>(1);
-  Handle<Object> value = args.at<Object>(2);
+  JSObject* recv = JSObject::cast(args[0]);
+  String* name = String::cast(args[1]);
+  Object* value = args[2];
    ASSERT(recv->HasNamedInterceptor());
    PropertyAttributes attr = NONE;
-  Handle<Object> result = SetPropertyWithInterceptor(recv, name, value,  
attr);
-
-  // SetPropertyWithInterceptor already converts a scheduled exception
-  // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION()  
here.
-
-  // Make sure to propagate exceptions.
-  if (result.is_null()) {
-    // Failure::Exception is converted to a null handle in the
-    // handle-based methods such as SetProperty.  We therefore need
-    // to convert null handles back to exceptions.
-    ASSERT(Top::has_pending_exception());
-    return Failure::Exception();
-  }
-  return *result;
+  Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
+  return result;
  }



Modified: trunk/test/cctest/test-api.cc
==============================================================================
--- trunk/test/cctest/test-api.cc       (original)
+++ trunk/test/cctest/test-api.cc       Thu Mar 19 15:21:34 2009
@@ -1254,6 +1254,78 @@
  }


+THREADED_TEST(IdentityHash) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  // Ensure that the test starts with an fresh heap to test whether the  
hash
+  // code is based on the address.
+  i::Heap::CollectAllGarbage();
+  Local<v8::Object> obj = v8::Object::New();
+  int hash = obj->GetIdentityHash();
+  int hash1 = obj->GetIdentityHash();
+  CHECK_EQ(hash, hash1);
+  int hash2 = v8::Object::New()->GetIdentityHash();
+  // Since the identity hash is essentially a random number two consecutive
+  // objects should not be assigned the same hash code. If the test below  
fails
+  // the random number generator should be evaluated.
+  CHECK_NE(hash, hash2);
+  i::Heap::CollectAllGarbage();
+  int hash3 = v8::Object::New()->GetIdentityHash();
+  // Make sure that the identity hash is not based on the initial address  
of
+  // the object alone. If the test below fails the random number generator
+  // should be evaluated.
+  CHECK_NE(hash, hash3);
+  int hash4 = obj->GetIdentityHash();
+  CHECK_EQ(hash, hash4);
+}
+
+
+THREADED_TEST(HiddenProperties) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  v8::Local<v8::Object> obj = v8::Object::New();
+  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
+  v8::Local<v8::String> empty = v8_str("");
+  v8::Local<v8::String> prop_name = v8_str("prop_name");
+
+  i::Heap::CollectAllGarbage();
+
+  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
+  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
+  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+
+  i::Heap::CollectAllGarbage();
+
+  // Make sure we do not find the hidden property.
+  CHECK(!obj->Has(empty));
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+  CHECK(obj->Get(empty)->IsUndefined());
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+  CHECK(obj->Set(empty, v8::Integer::New(2003)));
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
+
+  i::Heap::CollectAllGarbage();
+
+  // Add another property and delete it afterwards to force the object in
+  // slow case.
+  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+  CHECK(obj->Delete(prop_name));
+  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
+
+  i::Heap::CollectAllGarbage();
+
+  CHECK(obj->DeleteHiddenValue(key));
+  CHECK(obj->GetHiddenValue(key).IsEmpty());
+}
+
+
  THREADED_TEST(External) {
    v8::HandleScope scope;
    int x = 3;
@@ -5798,4 +5870,38 @@
    RegExpInterruptTest().RunTest();

    local_env->Exit();
+}
+
+
+// Verify that we can clone an object
+TEST(ObjectClone) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  const char* sample =
+    "var rv = {};"      \
+    "rv.alpha = 'hello';" \
+    "rv.beta = 123;"     \
+    "rv;";
+
+  // Create an object, verify basics.
+  Local<Value> val = CompileRun(sample);
+  CHECK(val->IsObject());
+  Local<v8::Object> obj = Local<v8::Object>::Cast(val);
+  obj->Set(v8_str("gamma"), v8_str("cloneme"));
+
+  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
+  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
+  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
+
+  // Clone it.
+  Local<v8::Object> clone = obj->Clone();
+  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
+  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
+  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
+
+  // Set a property on the clone, verify each object.
+  clone->Set(v8_str("beta"), v8::Integer::New(456));
+  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
+  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
  }

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

Reply via email to