Small API improvements:
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Mar 2010 18:47:03 +0000 (18:47 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Mar 2010 18:47:03 +0000 (18:47 +0000)
 * Added Get and Set taking uint32_t for faster and more convenient
   access to elements.

 * Added less verbose casting for handles. Now instead of
       v8::Local<v8::String>::Cast(args[0])
   one can write
       args[0].As<v8::String>().

Review URL: http://codereview.chromium.org/660243

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4002 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/handles.cc
src/handles.h
src/runtime.cc
src/runtime.h
test/cctest/test-api.cc

index 44338b9..f77c56a 100644 (file)
@@ -261,6 +261,10 @@ template <class T> class V8EXPORT_INLINE Handle {
     return Handle<T>(T::Cast(*that));
   }
 
+  template <class S> inline Handle<S> As() {
+    return Handle<S>::Cast(*this);
+  }
+
  private:
   T* val_;
 };
@@ -295,6 +299,10 @@ template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
     return Local<T>(T::Cast(*that));
   }
 
+  template <class S> inline Local<S> As() {
+    return Local<S>::Cast(*this);
+  }
+
   /** Create a local handle for the content of another handle.
    *  The referee is kept alive by the local handle even when
    *  the original handle is destroyed/disposed.
@@ -368,6 +376,10 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
     return Persistent<T>(T::Cast(*that));
   }
 
+  template <class S> inline Persistent<S> As() {
+    return Persistent<S>::Cast(*this);
+  }
+
   /**
    * Creates a new persistent handle for an existing local or
    * persistent handle.
@@ -1178,6 +1190,9 @@ class V8EXPORT Object : public Value {
            Handle<Value> value,
            PropertyAttribute attribs = None);
 
+  bool Set(uint32_t index,
+           Handle<Value> value);
+
   // Sets a local property on this object bypassing interceptors and
   // overriding accessors or read-only properties.
   //
@@ -1192,6 +1207,8 @@ class V8EXPORT Object : public Value {
 
   Local<Value> Get(Handle<Value> key);
 
+  Local<Value> Get(uint32_t index);
+
   // TODO(1245389): Replace the type-specific versions of these
   // functions with generic ones that accept a Handle<Value> key.
   bool Has(Handle<String> key);
index cb97e7f..53cb9d4 100644 (file)
@@ -1975,6 +1975,23 @@ bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
 }
 
 
+bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
+  ON_BAILOUT("v8::Object::Set()", return false);
+  ENTER_V8;
+  HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj = i::SetElement(
+      self,
+      index,
+      value_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(false);
+  return true;
+}
+
+
 bool v8::Object::ForceSet(v8::Handle<Value> key,
                           v8::Handle<Value> value,
                           v8::PropertyAttribute attribs) {
@@ -2023,6 +2040,18 @@ Local<Value> v8::Object::Get(v8::Handle<Value> key) {
 }
 
 
+Local<Value> v8::Object::Get(uint32_t index) {
+  ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
+  ENTER_V8;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = i::GetElement(self, index);
+  has_pending_exception = result.is_null();
+  EXCEPTION_BAILOUT_CHECK(Local<Value>());
+  return Utils::ToLocal(result);
+}
+
+
 Local<Value> v8::Object::GetPrototype() {
   ON_BAILOUT("v8::Object::GetPrototype()", return Local<v8::Value>());
   ENTER_V8;
index b019be9..c71d92b 100644 (file)
@@ -283,6 +283,12 @@ Handle<Object> GetProperty(Handle<Object> obj,
 }
 
 
+Handle<Object> GetElement(Handle<Object> obj,
+                          uint32_t index) {
+  CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object);
+}
+
+
 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
                                           Handle<JSObject> holder,
                                           Handle<String> name,
index b062a41..0c137a4 100644 (file)
@@ -233,6 +233,9 @@ Handle<Object> GetProperty(Handle<JSObject> obj,
 Handle<Object> GetProperty(Handle<Object> obj,
                            Handle<Object> key);
 
+Handle<Object> GetElement(Handle<Object> obj,
+                          uint32_t index);
+
 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
                                           Handle<JSObject> holder,
                                           Handle<String> name,
index 63f07f7..a116faa 100644 (file)
@@ -2857,6 +2857,11 @@ Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
     return prototype->GetElement(index);
   }
 
+  return GetElement(object, index);
+}
+
+
+Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
   return object->GetElement(index);
 }
 
index e4dc54b..2ce6a09 100644 (file)
@@ -403,6 +403,7 @@ class Runtime : public AllStatic {
   // Support getting the characters in a string using [] notation as
   // in Firefox/SpiderMonkey, Safari and Opera.
   static Object* GetElementOrCharAt(Handle<Object> object, uint32_t index);
+  static Object* GetElement(Handle<Object> object, uint32_t index);
 
   static Object* SetObjectProperty(Handle<Object> object,
                                    Handle<Object> key,
index e1223c1..68d89e5 100644 (file)
@@ -264,6 +264,25 @@ THREADED_TEST(Access) {
 }
 
 
+THREADED_TEST(AccessElement) {
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<v8::Object> obj = v8::Object::New();
+  Local<Value> before = obj->Get(1);
+  CHECK(before->IsUndefined());
+  Local<String> bar_str = v8_str("bar");
+  obj->Set(1, bar_str);
+  Local<Value> after = obj->Get(1);
+  CHECK(!after->IsUndefined());
+  CHECK(after->IsString());
+  CHECK_EQ(bar_str, after);
+
+  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
+  CHECK_EQ(v8_str("a"), value->Get(0));
+  CHECK_EQ(v8_str("b"), value->Get(1));
+}
+
+
 THREADED_TEST(Script) {
   v8::HandleScope scope;
   LocalContext env;
@@ -1254,7 +1273,7 @@ static v8::Handle<Value> CallFunctionRecursivelyCall(
   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   v8::Handle<Value> function =
       args.This()->Get(v8_str("callFunctionRecursively"));
-  return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
+  return function.As<Function>()->Call(args.This(), 0, NULL);
 }
 
 
@@ -1340,8 +1359,7 @@ THREADED_TEST(GlobalObjectInternalFields) {
   global_template->SetInternalFieldCount(1);
   LocalContext env(NULL, global_template);
   v8::Handle<v8::Object> global_proxy = env->Global();
-  v8::Handle<v8::Object> global =
-      v8::Handle<v8::Object>::Cast(global_proxy->GetPrototype());
+  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
   CHECK_EQ(1, global->InternalFieldCount());
   CHECK(global->GetInternalField(0)->IsUndefined());
   global->SetInternalField(0, v8_num(17));
@@ -1529,7 +1547,7 @@ THREADED_TEST(External) {
   LocalContext env;
   env->Global()->Set(v8_str("ext"), ext);
   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
-  v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
+  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
   int* ptr = static_cast<int*>(reext->Value());
   CHECK_EQ(x, 3);
   *ptr = 10;
@@ -1661,22 +1679,22 @@ THREADED_TEST(Array) {
   LocalContext context;
   Local<v8::Array> array = v8::Array::New();
   CHECK_EQ(0, array->Length());
-  CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
+  CHECK(array->Get(0)->IsUndefined());
   CHECK(!array->Has(0));
-  CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
+  CHECK(array->Get(100)->IsUndefined());
   CHECK(!array->Has(100));
-  array->Set(v8::Integer::New(2), v8_num(7));
+  array->Set(2, v8_num(7));
   CHECK_EQ(3, array->Length());
   CHECK(!array->Has(0));
   CHECK(!array->Has(1));
   CHECK(array->Has(2));
-  CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(7, array->Get(2)->Int32Value());
   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
-  Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
+  Local<v8::Array> arr = obj.As<v8::Array>();
   CHECK_EQ(3, arr->Length());
-  CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(1, arr->Get(0)->Int32Value());
+  CHECK_EQ(2, arr->Get(1)->Int32Value());
+  CHECK_EQ(3, arr->Get(2)->Int32Value());
 }
 
 
@@ -1685,7 +1703,7 @@ v8::Handle<Value> HandleF(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
   Local<v8::Array> result = v8::Array::New(args.Length());
   for (int i = 0; i < args.Length(); i++)
-    result->Set(v8::Integer::New(i), args[i]);
+    result->Set(i, args[i]);
   return scope.Close(result);
 }
 
@@ -1697,39 +1715,34 @@ THREADED_TEST(Vector) {
   LocalContext context(0, global);
 
   const char* fun = "f()";
-  Local<v8::Array> a0 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
+  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   CHECK_EQ(0, a0->Length());
 
   const char* fun2 = "f(11)";
-  Local<v8::Array> a1 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
+  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   CHECK_EQ(1, a1->Length());
-  CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(11, a1->Get(0)->Int32Value());
 
   const char* fun3 = "f(12, 13)";
-  Local<v8::Array> a2 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
+  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   CHECK_EQ(2, a2->Length());
-  CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
+  CHECK_EQ(12, a2->Get(0)->Int32Value());
+  CHECK_EQ(13, a2->Get(1)->Int32Value());
 
   const char* fun4 = "f(14, 15, 16)";
-  Local<v8::Array> a3 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
+  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   CHECK_EQ(3, a3->Length());
-  CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(14, a3->Get(0)->Int32Value());
+  CHECK_EQ(15, a3->Get(1)->Int32Value());
+  CHECK_EQ(16, a3->Get(2)->Int32Value());
 
   const char* fun5 = "f(17, 18, 19, 20)";
-  Local<v8::Array> a4 =
-      Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
+  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   CHECK_EQ(4, a4->Length());
-  CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
-  CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
-  CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
-  CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
+  CHECK_EQ(17, a4->Get(0)->Int32Value());
+  CHECK_EQ(18, a4->Get(1)->Int32Value());
+  CHECK_EQ(19, a4->Get(2)->Int32Value());
+  CHECK_EQ(20, a4->Get(3)->Int32Value());
 }
 
 
@@ -2145,8 +2158,7 @@ v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
                                  args[3] };
     if (count % cInterval == 0) {
       v8::TryCatch try_catch;
-      Local<Value> result =
-          v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
       int expected = args[3]->Int32Value();
       if (try_catch.HasCaught()) {
         CHECK_EQ(expected, count);
@@ -2157,7 +2169,7 @@ v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
       }
       return result;
     } else {
-      return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+      return fun.As<Function>()->Call(global, 4, argv);
     }
   }
 }
@@ -2547,7 +2559,7 @@ static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
                                                const AccessorInfo& info) {
   // Set x on the prototype object and do not handle the get request.
   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
-  v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
+  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
   return v8::Handle<Value>();
 }
 
@@ -2883,22 +2895,22 @@ THREADED_TEST(FunctionPrototypeAcrossContexts) {
   v8::Handle<v8::Object> global0 =
       env0->Global();
   v8::Handle<v8::Object> object0 =
-      v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
+      global0->Get(v8_str("Object")).As<v8::Object>();
   v8::Handle<v8::Object> tostring0 =
-      v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
+      object0->Get(v8_str("toString")).As<v8::Object>();
   v8::Handle<v8::Object> proto0 =
-      v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
+      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
   proto0->Set(v8_str("custom"), v8_num(1234));
 
   LocalContext env1;
   v8::Handle<v8::Object> global1 =
       env1->Global();
   v8::Handle<v8::Object> object1 =
-      v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
+      global1->Get(v8_str("Object")).As<v8::Object>();
   v8::Handle<v8::Object> tostring1 =
-      v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
+      object1->Get(v8_str("toString")).As<v8::Object>();
   v8::Handle<v8::Object> proto1 =
-      v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
+      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
   CHECK(!proto1->Has(v8_str("custom")));
 }
 
@@ -3520,7 +3532,7 @@ THREADED_TEST(Arguments) {
   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
   LocalContext context(NULL, global);
-  args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
+  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
   v8_compile("f(1, 2, 3)")->Run();
 }
 
@@ -3858,21 +3870,20 @@ THREADED_TEST(ErrorConstruction) {
   v8::Handle<String> message = v8_str("message");
   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
   CHECK(range_error->IsObject());
-  v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
-  CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
+  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
+  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
   CHECK(reference_error->IsObject());
-  CHECK(
-      v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
+  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
   CHECK(syntax_error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
+  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
   CHECK(type_error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
+  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
   v8::Handle<Value> error = v8::Exception::Error(foo);
   CHECK(error->IsObject());
-  CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
+  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
 }
 
 
@@ -4795,13 +4806,13 @@ static bool NamedAccessFlatten(Local<v8::Object> global,
   CHECK(name->IsString());
 
   memset(buf, 0x1, sizeof(buf));
-  len = Local<String>::Cast(name)->WriteAscii(buf);
+  len = name.As<String>()->WriteAscii(buf);
   CHECK_EQ(4, len);
 
   uint16_t buf2[100];
 
   memset(buf, 0x1, sizeof(buf));
-  len = Local<String>::Cast(name)->Write(buf2);
+  len = name.As<String>()->Write(buf2);
   CHECK_EQ(4, len);
 
   return true;
@@ -5150,7 +5161,7 @@ THREADED_TEST(HiddenPrototype) {
   // object.
   Local<Value> proto = o0->Get(v8_str("__proto__"));
   CHECK(proto->IsObject());
-  CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
+  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
 }
 
 
@@ -5194,20 +5205,20 @@ THREADED_TEST(SetPrototype) {
   // object.
   Local<Value> proto = o0->Get(v8_str("__proto__"));
   CHECK(proto->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto), o3);
+  CHECK_EQ(proto.As<v8::Object>(), o3);
 
   // However, Object::GetPrototype ignores hidden prototype.
   Local<Value> proto0 = o0->GetPrototype();
   CHECK(proto0->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto0), o1);
+  CHECK_EQ(proto0.As<v8::Object>(), o1);
 
   Local<Value> proto1 = o1->GetPrototype();
   CHECK(proto1->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto1), o2);
+  CHECK_EQ(proto1.As<v8::Object>(), o2);
 
   Local<Value> proto2 = o2->GetPrototype();
   CHECK(proto2->IsObject());
-  CHECK_EQ(v8::Handle<v8::Object>::Cast(proto2), o3);
+  CHECK_EQ(proto2.As<v8::Object>(), o3);
 }
 
 
@@ -6919,7 +6930,7 @@ THREADED_TEST(ObjectProtoToString) {
 
   // Check ordinary object
   Local<Value> object = v8_compile("new Object()")->Run();
-  value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
+  value = object.As<v8::Object>()->ObjectProtoToString();
   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
 }
 
@@ -7539,12 +7550,12 @@ THREADED_TEST(DateAccess) {
   LocalContext context;
   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
   CHECK(date->IsDate());
-  CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
+  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
 }
 
 
 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
-  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
+  v8::Handle<v8::Object> obj = val.As<v8::Object>();
   v8::Handle<v8::Array> props = obj->GetPropertyNames();
   CHECK_EQ(elmc, props->Length());
   for (int i = 0; i < elmc; i++) {
@@ -7566,7 +7577,7 @@ THREADED_TEST(PropertyEnumeration) {
       "var x = { __proto__: proto, w: 0, z: 1 };"
       "result[3] = x;"
       "result;"))->Run();
-  v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
+  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
   CHECK_EQ(4, elms->Length());
   int elmc0 = 0;
   const char** elmv0 = NULL;
@@ -8088,7 +8099,7 @@ TEST(ObjectClone) {
   // Create an object, verify basics.
   Local<Value> val = CompileRun(sample);
   CHECK(val->IsObject());
-  Local<v8::Object> obj = Local<v8::Object>::Cast(val);
+  Local<v8::Object> obj = val.As<v8::Object>();
   obj->Set(v8_str("gamma"), v8_str("cloneme"));
 
   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));