Revision: 14210
Author:   [email protected]
Date:     Wed Apr 10 05:16:29 2013
Log:      ES6 symbols: extend V8 API to support symbols

Specifically:
- Introduce Symbol and SymbolObject classes.
- Generalise Object::Has and Object::Delete to arbitrary Value-typed keys.
- Generalise some places in the API implementation from String to Name.

It is not possible to intercept symbol-named properties. That is consistent with the idea that symbols are private and should not leak.

[email protected]
BUG=v8:2158

Review URL: https://codereview.chromium.org/13626002
http://code.google.com/p/v8/source/detail?r=14210

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/api.h
 /branches/bleeding_edge/src/handles.cc
 /branches/bleeding_edge/src/handles.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/include/v8.h        Wed Apr 10 02:34:37 2013
+++ /branches/bleeding_edge/include/v8.h        Wed Apr 10 05:16:29 2013
@@ -127,6 +127,8 @@
 class StackTrace;
 class String;
 class StringObject;
+class Symbol;
+class SymbolObject;
 class Uint32;
 class Utils;
 class Value;
@@ -972,6 +974,12 @@
    */
   V8_INLINE(bool IsString() const);

+  /**
+   * Returns true if this value is a symbol.
+   * This is an experimental feature.
+   */
+  bool IsSymbol() const;
+
   /**
    * Returns true if this value is a function.
    */
@@ -1032,6 +1040,12 @@
    */
   bool IsStringObject() const;

+  /**
+   * Returns true if this value is a Symbol object.
+   * This is an experimental feature.
+   */
+  bool IsSymbolObject() const;
+
   /**
    * Returns true if this value is a NativeError.
    */
@@ -1311,7 +1325,11 @@
   /** Allocates a new string from 16-bit character codes.*/
   static Local<String> New(const uint16_t* data, int length = -1);

-  /** Creates a symbol. Returns one if it exists already.*/
+  /**
+   * Creates an internalized string (historically called a "symbol",
+ * not to be confused with ES6 symbols). Returns one if it exists already.
+   * TODO(rossberg): Deprecate me when the new string API is here.
+   */
   static Local<String> NewSymbol(const char* data, int length = -1);

   /**
@@ -1449,6 +1467,29 @@
 };


+/**
+ * A JavaScript symbol (ECMA-262 edition 6)
+ *
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8EXPORT Symbol : public Primitive {
+ public:
+  // Returns the print name string of the symbol, or undefined if none.
+  Local<Value> Name() const;
+
+  // Create a symbol without a print name.
+  static Local<Symbol> New(Isolate* isolate);
+
+  // Create a symbol with a print name.
+ static Local<Symbol> New(Isolate *isolate, const char* data, int length = -1);
+
+  V8_INLINE(static Symbol* Cast(v8::Value* obj));
+ private:
+  Symbol();
+  static void CheckCast(v8::Value* obj);
+};
+
+
 /**
  * A JavaScript number value (ECMA-262, 4.3.20)
  */
@@ -1590,11 +1631,9 @@
    */
   PropertyAttribute GetPropertyAttributes(Handle<Value> key);

-  // TODO(1245389): Replace the type-specific versions of these
-  // functions with generic ones that accept a Handle<Value> key.
-  bool Has(Handle<String> key);
+  bool Has(Handle<Value> key);

-  bool Delete(Handle<String> key);
+  bool Delete(Handle<Value> key);

   // Delete a property on this object bypassing interceptors and
   // ignoring dont-delete attributes.
@@ -1976,6 +2015,27 @@

   V8_INLINE(static StringObject* Cast(v8::Value* obj));

+ private:
+  static void CheckCast(v8::Value* obj);
+};
+
+
+/**
+ * A Symbol object (ECMA-262 edition 6).
+ *
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8EXPORT SymbolObject : public Object {
+ public:
+  static Local<Value> New(Isolate* isolate, Handle<Symbol> value);
+
+  /**
+   * Returns the Symbol held by the object.
+   */
+  Local<Symbol> SymbolValue() const;
+
+  V8_INLINE(static SymbolObject* Cast(v8::Value* obj));
+
  private:
   static void CheckCast(v8::Value* obj);
 };
@@ -4857,6 +4917,14 @@
   if (!I::HasHeapObjectTag(obj)) return false;
   return (I::GetInstanceType(obj) < I::kFirstNonstringType);
 }
+
+
+Symbol* Symbol::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<Symbol*>(value);
+}


 Number* Number::Cast(v8::Value* value) {
@@ -4889,6 +4957,14 @@
 #endif
   return static_cast<StringObject*>(value);
 }
+
+
+SymbolObject* SymbolObject::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<SymbolObject*>(value);
+}


 NumberObject* NumberObject::Cast(v8::Value* value) {
=======================================
--- /branches/bleeding_edge/src/api.cc  Wed Apr 10 02:34:37 2013
+++ /branches/bleeding_edge/src/api.cc  Wed Apr 10 05:16:29 2013
@@ -2365,6 +2365,12 @@
   ASSERT_EQ(result, QuickIsString());
   return result;
 }
+
+
+bool Value::IsSymbol() const {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsSymbol()")) return false;
+  return Utils::OpenHandle(this)->IsSymbol();
+}


 bool Value::IsArray() const {
@@ -2449,6 +2455,16 @@
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   return obj->HasSpecificClassOf(isolate->heap()->String_string());
 }
+
+
+bool Value::IsSymbolObject() const {
+  // TODO(svenpanne): these and other test functions should be written such
+  // that they do not use Isolate::Current().
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::Value::IsSymbolObject()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return obj->HasSpecificClassOf(isolate->heap()->Symbol_string());
+}


 bool Value::IsNumberObject() const {
@@ -2662,6 +2678,15 @@
            "v8::String::Cast()",
            "Could not convert to string");
 }
+
+
+void v8::Symbol::CheckCast(v8::Value* that) {
+  if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Cast()")) return;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsSymbol(),
+           "v8::Symbol::Cast()",
+           "Could not convert to symbol");
+}


 void v8::Number::CheckCast(v8::Value* that) {
@@ -2709,6 +2734,16 @@
            "v8::StringObject::Cast()",
            "Could not convert to StringObject");
 }
+
+
+void v8::SymbolObject::CheckCast(v8::Value* that) {
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::SymbolObject::Cast()")) return;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Symbol_string()),
+           "v8::SymbolObject::Cast()",
+           "Could not convert to SymbolObject");
+}


 void v8::NumberObject::CheckCast(v8::Value* that) {
@@ -3079,13 +3114,13 @@
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  if (!key_obj->IsString()) {
+  if (!key_obj->IsName()) {
     EXCEPTION_PREAMBLE(isolate);
     key_obj = i::Execution::ToString(key_obj, &has_pending_exception);
     EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
   }
-  i::Handle<i::String> key_string = i::Handle<i::String>::cast(key_obj);
-  PropertyAttributes result = self->GetPropertyAttribute(*key_string);
+  i::Handle<i::Name> key_name = i::Handle<i::Name>::cast(key_obj);
+  PropertyAttributes result = self->GetPropertyAttribute(*key_name);
   if (result == ABSENT) return static_cast<PropertyAttribute>(NONE);
   return static_cast<PropertyAttribute>(result);
 }
@@ -3255,24 +3290,32 @@
 }


-bool v8::Object::Delete(v8::Handle<String> key) {
+bool v8::Object::Delete(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Delete()", return false);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  return i::JSObject::DeleteProperty(self, key_obj)->IsTrue();
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> obj = i::DeleteProperty(self, key_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(isolate, false);
+  return obj->IsTrue();
 }


-bool v8::Object::Has(v8::Handle<String> key) {
+bool v8::Object::Has(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Has()", return false);
   ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  return self->HasProperty(*key_obj);
+  i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> obj = i::HasProperty(self, key_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(isolate, false);
+  return obj->IsTrue();
 }


@@ -4591,6 +4634,15 @@
     return NULL;
   }
 }
+
+
+Local<Value> Symbol::Name() const {
+  if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Name()"))
+    return Local<Value>();
+  i::Handle<i::Symbol> sym = Utils::OpenHandle(this);
+  i::Handle<i::Object> name(sym->name(), sym->GetIsolate());
+  return Utils::ToLocal(name);
+}


 double Number::Value() const {
@@ -5455,6 +5507,29 @@
   return Utils::ToLocal(
       i::Handle<i::String>(i::String::cast(jsvalue->value())));
 }
+
+
+Local<v8::Value> v8::SymbolObject::New(Isolate* isolate, Handle<Symbol> value) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::SymbolObject::New()");
+  LOG_API(i_isolate, "SymbolObject::New");
+  ENTER_V8(i_isolate);
+  i::Handle<i::Object> obj =
+      i_isolate->factory()->ToObject(Utils::OpenHandle(*value));
+  return Utils::ToLocal(obj);
+}
+
+
+Local<v8::Symbol> v8::SymbolObject::SymbolValue() const {
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::SymbolObject::SymbolValue()"))
+    return Local<v8::Symbol>();
+  LOG_API(isolate, "SymbolObject::SymbolValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
+  return Utils::ToLocal(
+      i::Handle<i::Symbol>(i::Symbol::cast(jsvalue->value())));
+}


 Local<v8::Value> v8::Date::New(double time) {
@@ -5636,6 +5711,30 @@
       i::Vector<const char>(data, length));
   return Utils::ToLocal(result);
 }
+
+
+Local<Symbol> v8::Symbol::New(Isolate* isolate) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+  LOG_API(i_isolate, "Symbol::New()");
+  ENTER_V8(i_isolate);
+  i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+  return Utils::ToLocal(result);
+}
+
+
+Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+  LOG_API(i_isolate, "Symbol::New(char)");
+  ENTER_V8(i_isolate);
+  if (length == -1) length = i::StrLength(data);
+  i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
+      i::Vector<const char>(data, length));
+  i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+  result->set_name(*name);
+  return Utils::ToLocal(result);
+}


 Local<Number> v8::Number::New(double value) {
=======================================
--- /branches/bleeding_edge/src/api.h   Fri Mar 22 06:40:13 2013
+++ /branches/bleeding_edge/src/api.h   Wed Apr 10 05:16:29 2013
@@ -171,6 +171,7 @@
   V(Object, JSObject)                          \
   V(Array, JSArray)                            \
   V(String, String)                            \
+  V(Symbol, Symbol)                            \
   V(Script, Object)                            \
   V(Function, JSFunction)                      \
   V(Message, JSObject)                         \
@@ -196,6 +197,8 @@
       v8::internal::Handle<v8::internal::JSFunction> obj);
   static inline Local<String> ToLocal(
       v8::internal::Handle<v8::internal::String> obj);
+  static inline Local<Symbol> ToLocal(
+      v8::internal::Handle<v8::internal::Symbol> obj);
   static inline Local<RegExp> ToLocal(
       v8::internal::Handle<v8::internal::JSRegExp> obj);
   static inline Local<Object> ToLocal(
@@ -268,6 +271,7 @@
 MAKE_TO_LOCAL(ToLocal, Object, Value)
 MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
 MAKE_TO_LOCAL(ToLocal, String, String)
+MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
 MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
 MAKE_TO_LOCAL(ToLocal, JSObject, Object)
 MAKE_TO_LOCAL(ToLocal, JSArray, Array)
=======================================
--- /branches/bleeding_edge/src/handles.cc      Fri Mar 22 07:33:27 2013
+++ /branches/bleeding_edge/src/handles.cc      Wed Apr 10 05:16:29 2013
@@ -250,15 +250,32 @@
           isolate, object, key, value, attributes),
       Object);
 }
+
+
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) {
+  Isolate* isolate = object->GetIsolate();
+  CALL_HEAP_FUNCTION(isolate,
+                     Runtime::DeleteObjectProperty(
+ isolate, object, key, JSReceiver::NORMAL_DELETION),
+                     Object);
+}


 Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
                                    Handle<Object> key) {
   Isolate* isolate = object->GetIsolate();
   CALL_HEAP_FUNCTION(isolate,
- Runtime::ForceDeleteObjectProperty(isolate, object, key),
+                     Runtime::DeleteObjectProperty(
+                         isolate, object, key, JSReceiver::FORCE_DELETION),
                      Object);
 }
+
+
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) {
+  Isolate* isolate = obj->GetIsolate();
+  CALL_HEAP_FUNCTION(isolate,
+ Runtime::HasObjectProperty(isolate, obj, key), Object);
+}


 Handle<Object> GetProperty(Handle<JSReceiver> obj,
=======================================
--- /branches/bleeding_edge/src/handles.h       Fri Mar 22 07:33:27 2013
+++ /branches/bleeding_edge/src/handles.h       Wed Apr 10 05:16:29 2013
@@ -223,11 +223,13 @@
                                 Handle<Object> value,
                                 PropertyAttributes attributes);

-Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
-                                   Handle<Object> key);
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key);

-Handle<Object> GetProperty(Handle<JSReceiver> obj,
-                           const char* name);
+Handle<Object> ForceDeleteProperty(Handle<JSObject> object, Handle<Object> key);
+
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key);
+
+Handle<Object> GetProperty(Handle<JSReceiver> obj, const char* name);

 Handle<Object> GetProperty(Isolate* isolate,
                            Handle<Object> obj,
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Wed Apr 10 02:24:31 2013
+++ /branches/bleeding_edge/src/runtime.cc      Wed Apr 10 05:16:29 2013
@@ -3945,6 +3945,33 @@

   return object->GetElement(index);
 }
+
+
+MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
+                                        Handle<JSReceiver> object,
+                                        Handle<Object> key) {
+  HandleScope scope(isolate);
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    return isolate->heap()->ToBoolean(object->HasElement(index));
+  }
+
+  // Convert the key to a name - possibly by calling back into JavaScript.
+  Handle<Name> name;
+  if (key->IsName()) {
+    name = Handle<Name>::cast(key);
+  } else {
+    bool has_pending_exception = false;
+    Handle<Object> converted =
+        Execution::ToString(key, &has_pending_exception);
+    if (has_pending_exception) return Failure::Exception();
+    name = Handle<Name>::cast(converted);
+  }
+
+  return isolate->heap()->ToBoolean(object->HasProperty(*name));
+}


 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
@@ -4364,9 +4391,10 @@
 }


-MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
- Handle<JSReceiver> receiver,
-                                                Handle<Object> key) {
+MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
+                                           Handle<JSReceiver> receiver,
+                                           Handle<Object> key,
+                                           JSReceiver::DeleteMode mode) {
   HandleScope scope(isolate);

   // Check if the given key is an array index.
@@ -4382,7 +4410,7 @@
       return isolate->heap()->true_value();
     }

-    return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
+    return receiver->DeleteElement(index, mode);
   }

   Handle<Name> name;
@@ -4397,7 +4425,7 @@
   }

   if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
-  return receiver->DeleteProperty(*name, JSReceiver::FORCE_DELETION);
+  return receiver->DeleteProperty(*name, mode);
 }


=======================================
--- /branches/bleeding_edge/src/runtime.h       Fri Apr  5 04:57:02 2013
+++ /branches/bleeding_edge/src/runtime.h       Wed Apr 10 05:16:29 2013
@@ -699,7 +699,13 @@
       Handle<Object> value,
       PropertyAttributes attr);

-  MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
+  MUST_USE_RESULT static MaybeObject* DeleteObjectProperty(
+      Isolate* isolate,
+      Handle<JSReceiver> object,
+      Handle<Object> key,
+      JSReceiver::DeleteMode mode);
+
+  MUST_USE_RESULT static MaybeObject* HasObjectProperty(
       Isolate* isolate,
       Handle<JSReceiver> object,
       Handle<Object> key);
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Tue Apr  9 00:34:32 2013
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Wed Apr 10 05:16:29 2013
@@ -2176,6 +2176,88 @@
     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   }
 }
+
+
+THREADED_TEST(SymbolProperties) {
+  i::FLAG_harmony_symbols = true;
+
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  v8::Local<v8::Object> obj = v8::Object::New();
+  v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
+  v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
+
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  // Check basic symbol functionality.
+  CHECK(sym1->IsSymbol());
+  CHECK(sym2->IsSymbol());
+  CHECK(!obj->IsSymbol());
+
+  CHECK(sym1->Equals(sym1));
+  CHECK(sym2->Equals(sym2));
+  CHECK(!sym1->Equals(sym2));
+  CHECK(!sym2->Equals(sym1));
+  CHECK(sym1->StrictEquals(sym1));
+  CHECK(sym2->StrictEquals(sym2));
+  CHECK(!sym1->StrictEquals(sym2));
+  CHECK(!sym2->StrictEquals(sym1));
+
+  CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
+
+  v8::Local<v8::Value> sym_val = sym2;
+  CHECK(sym_val->IsSymbol());
+  CHECK(sym_val->Equals(sym2));
+  CHECK(sym_val->StrictEquals(sym2));
+  CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
+
+  v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
+  CHECK(sym_obj->IsSymbolObject());
+  CHECK(!sym2->IsSymbolObject());
+  CHECK(!obj->IsSymbolObject());
+  CHECK(sym_obj->Equals(sym2));
+  CHECK(!sym_obj->StrictEquals(sym2));
+  CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
+  CHECK(v8::SymbolObject::Cast(*sym_obj)->SymbolValue()->Equals(sym2));
+
+  // Make sure delete of a non-existent symbol property works.
+  CHECK(obj->Delete(sym1));
+  CHECK(!obj->Has(sym1));
+
+  CHECK(obj->Set(sym1, v8::Integer::New(1503)));
+  CHECK(obj->Has(sym1));
+  CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
+  CHECK(obj->Set(sym1, v8::Integer::New(2002)));
+  CHECK(obj->Has(sym1));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
+
+  CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
+  int num_props = obj->GetPropertyNames()->Length();
+  CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+  CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
+
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  // Add another property and delete it afterwards to force the object in
+  // slow case.
+  CHECK(obj->Set(sym2, v8::Integer::New(2008)));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+
+  CHECK(obj->Has(sym1));
+  CHECK(obj->Has(sym2));
+  CHECK(obj->Delete(sym2));
+  CHECK(obj->Has(sym1));
+  CHECK(!obj->Has(sym2));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+}


 THREADED_TEST(HiddenProperties) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to