From 9f681fa9d609b0f2014f33b6930e55da43a1bd17 Mon Sep 17 00:00:00 2001 From: "vitalyr@chromium.org" Date: Tue, 2 Mar 2010 18:47:03 +0000 Subject: [PATCH] Small API improvements: * 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::Cast(args[0]) one can write args[0].As(). 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 | 17 ++++++ src/api.cc | 29 ++++++++++ src/handles.cc | 6 +++ src/handles.h | 3 ++ src/runtime.cc | 5 ++ src/runtime.h | 1 + test/cctest/test-api.cc | 137 ++++++++++++++++++++++++++---------------------- 7 files changed, 135 insertions(+), 63 deletions(-) diff --git a/include/v8.h b/include/v8.h index 44338b9..f77c56a 100644 --- a/include/v8.h +++ b/include/v8.h @@ -261,6 +261,10 @@ template class V8EXPORT_INLINE Handle { return Handle(T::Cast(*that)); } + template inline Handle As() { + return Handle::Cast(*this); + } + private: T* val_; }; @@ -295,6 +299,10 @@ template class V8EXPORT_INLINE Local : public Handle { return Local(T::Cast(*that)); } + template inline Local As() { + return Local::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 V8EXPORT_INLINE Persistent : public Handle { return Persistent(T::Cast(*that)); } + template inline Persistent As() { + return Persistent::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, PropertyAttribute attribs = None); + bool Set(uint32_t index, + Handle 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 Get(Handle key); + Local Get(uint32_t index); + // TODO(1245389): Replace the type-specific versions of these // functions with generic ones that accept a Handle key. bool Has(Handle key); diff --git a/src/api.cc b/src/api.cc index cb97e7f..53cb9d4 100644 --- a/src/api.cc +++ b/src/api.cc @@ -1975,6 +1975,23 @@ bool v8::Object::Set(v8::Handle key, v8::Handle value, } +bool v8::Object::Set(uint32_t index, v8::Handle value) { + ON_BAILOUT("v8::Object::Set()", return false); + ENTER_V8; + HandleScope scope; + i::Handle self = Utils::OpenHandle(this); + i::Handle value_obj = Utils::OpenHandle(*value); + EXCEPTION_PREAMBLE(); + i::Handle 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 key, v8::Handle value, v8::PropertyAttribute attribs) { @@ -2023,6 +2040,18 @@ Local v8::Object::Get(v8::Handle key) { } +Local v8::Object::Get(uint32_t index) { + ON_BAILOUT("v8::Object::Get()", return Local()); + ENTER_V8; + i::Handle self = Utils::OpenHandle(this); + EXCEPTION_PREAMBLE(); + i::Handle result = i::GetElement(self, index); + has_pending_exception = result.is_null(); + EXCEPTION_BAILOUT_CHECK(Local()); + return Utils::ToLocal(result); +} + + Local v8::Object::GetPrototype() { ON_BAILOUT("v8::Object::GetPrototype()", return Local()); ENTER_V8; diff --git a/src/handles.cc b/src/handles.cc index b019be9..c71d92b 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -283,6 +283,12 @@ Handle GetProperty(Handle obj, } +Handle GetElement(Handle obj, + uint32_t index) { + CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object); +} + + Handle GetPropertyWithInterceptor(Handle receiver, Handle holder, Handle name, diff --git a/src/handles.h b/src/handles.h index b062a41..0c137a4 100644 --- a/src/handles.h +++ b/src/handles.h @@ -233,6 +233,9 @@ Handle GetProperty(Handle obj, Handle GetProperty(Handle obj, Handle key); +Handle GetElement(Handle obj, + uint32_t index); + Handle GetPropertyWithInterceptor(Handle receiver, Handle holder, Handle name, diff --git a/src/runtime.cc b/src/runtime.cc index 63f07f7..a116faa 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2857,6 +2857,11 @@ Object* Runtime::GetElementOrCharAt(Handle object, uint32_t index) { return prototype->GetElement(index); } + return GetElement(object, index); +} + + +Object* Runtime::GetElement(Handle object, uint32_t index) { return object->GetElement(index); } diff --git a/src/runtime.h b/src/runtime.h index e4dc54b..2ce6a09 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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, uint32_t index); + static Object* GetElement(Handle object, uint32_t index); static Object* SetObjectProperty(Handle object, Handle key, diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index e1223c1..68d89e5 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -264,6 +264,25 @@ THREADED_TEST(Access) { } +THREADED_TEST(AccessElement) { + v8::HandleScope scope; + LocalContext env; + Local obj = v8::Object::New(); + Local before = obj->Get(1); + CHECK(before->IsUndefined()); + Local bar_str = v8_str("bar"); + obj->Set(1, bar_str); + Local after = obj->Get(1); + CHECK(!after->IsUndefined()); + CHECK(after->IsString()); + CHECK_EQ(bar_str, after); + + Local value = CompileRun("[\"a\", \"b\"]").As(); + 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 CallFunctionRecursivelyCall( args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); v8::Handle function = args.This()->Get(v8_str("callFunctionRecursively")); - return v8::Handle::Cast(function)->Call(args.This(), 0, NULL); + return function.As()->Call(args.This(), 0, NULL); } @@ -1340,8 +1359,7 @@ THREADED_TEST(GlobalObjectInternalFields) { global_template->SetInternalFieldCount(1); LocalContext env(NULL, global_template); v8::Handle global_proxy = env->Global(); - v8::Handle global = - v8::Handle::Cast(global_proxy->GetPrototype()); + v8::Handle global = global_proxy->GetPrototype().As(); 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 reext_obj = Script::Compile(v8_str("this.ext"))->Run(); - v8::Handle reext = v8::Handle::Cast(reext_obj); + v8::Handle reext = reext_obj.As(); int* ptr = static_cast(reext->Value()); CHECK_EQ(x, 3); *ptr = 10; @@ -1661,22 +1679,22 @@ THREADED_TEST(Array) { LocalContext context; Local 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 obj = Script::Compile(v8_str("[1, 2, 3]"))->Run(); - Local arr = Local::Cast(obj); + Local arr = obj.As(); 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 HandleF(const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); Local 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 a0 = - Local::Cast(Script::Compile(String::New(fun))->Run()); + Local a0 = CompileRun(fun).As(); CHECK_EQ(0, a0->Length()); const char* fun2 = "f(11)"; - Local a1 = - Local::Cast(Script::Compile(String::New(fun2))->Run()); + Local a1 = CompileRun(fun2).As(); 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 a2 = - Local::Cast(Script::Compile(String::New(fun3))->Run()); + Local a2 = CompileRun(fun3).As(); 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 a3 = - Local::Cast(Script::Compile(String::New(fun4))->Run()); + Local a3 = CompileRun(fun4).As(); 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 a4 = - Local::Cast(Script::Compile(String::New(fun5))->Run()); + Local a4 = CompileRun(fun5).As(); 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 CThrowCountDown(const v8::Arguments& args) { args[3] }; if (count % cInterval == 0) { v8::TryCatch try_catch; - Local result = - v8::Handle::Cast(fun)->Call(global, 4, argv); + Local result = fun.As()->Call(global, 4, argv); int expected = args[3]->Int32Value(); if (try_catch.HasCaught()) { CHECK_EQ(expected, count); @@ -2157,7 +2169,7 @@ v8::Handle CThrowCountDown(const v8::Arguments& args) { } return result; } else { - return v8::Handle::Cast(fun)->Call(global, 4, argv); + return fun.As()->Call(global, 4, argv); } } } @@ -2547,7 +2559,7 @@ static v8::Handle SetXOnPrototypeGetter(Local property, const AccessorInfo& info) { // Set x on the prototype object and do not handle the get request. v8::Handle proto = info.Holder()->GetPrototype(); - v8::Handle::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23)); + proto.As()->Set(v8_str("x"), v8::Integer::New(23)); return v8::Handle(); } @@ -2883,22 +2895,22 @@ THREADED_TEST(FunctionPrototypeAcrossContexts) { v8::Handle global0 = env0->Global(); v8::Handle object0 = - v8::Handle::Cast(global0->Get(v8_str("Object"))); + global0->Get(v8_str("Object")).As(); v8::Handle tostring0 = - v8::Handle::Cast(object0->Get(v8_str("toString"))); + object0->Get(v8_str("toString")).As(); v8::Handle proto0 = - v8::Handle::Cast(tostring0->Get(v8_str("__proto__"))); + tostring0->Get(v8_str("__proto__")).As(); proto0->Set(v8_str("custom"), v8_num(1234)); LocalContext env1; v8::Handle global1 = env1->Global(); v8::Handle object1 = - v8::Handle::Cast(global1->Get(v8_str("Object"))); + global1->Get(v8_str("Object")).As(); v8::Handle tostring1 = - v8::Handle::Cast(object1->Get(v8_str("toString"))); + object1->Get(v8_str("toString")).As(); v8::Handle proto1 = - v8::Handle::Cast(tostring1->Get(v8_str("__proto__"))); + tostring1->Get(v8_str("__proto__")).As(); CHECK(!proto1->Has(v8_str("custom"))); } @@ -3520,7 +3532,7 @@ THREADED_TEST(Arguments) { v8::Handle global = ObjectTemplate::New(); global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback)); LocalContext context(NULL, global); - args_fun = v8::Handle::Cast(context->Global()->Get(v8_str("f"))); + args_fun = context->Global()->Get(v8_str("f")).As(); v8_compile("f(1, 2, 3)")->Run(); } @@ -3858,21 +3870,20 @@ THREADED_TEST(ErrorConstruction) { v8::Handle message = v8_str("message"); v8::Handle range_error = v8::Exception::RangeError(foo); CHECK(range_error->IsObject()); - v8::Handle range_obj(v8::Handle::Cast(range_error)); - CHECK(v8::Handle::Cast(range_error)->Get(message)->Equals(foo)); + v8::Handle range_obj = range_error.As(); + CHECK(range_error.As()->Get(message)->Equals(foo)); v8::Handle reference_error = v8::Exception::ReferenceError(foo); CHECK(reference_error->IsObject()); - CHECK( - v8::Handle::Cast(reference_error)->Get(message)->Equals(foo)); + CHECK(reference_error.As()->Get(message)->Equals(foo)); v8::Handle syntax_error = v8::Exception::SyntaxError(foo); CHECK(syntax_error->IsObject()); - CHECK(v8::Handle::Cast(syntax_error)->Get(message)->Equals(foo)); + CHECK(syntax_error.As()->Get(message)->Equals(foo)); v8::Handle type_error = v8::Exception::TypeError(foo); CHECK(type_error->IsObject()); - CHECK(v8::Handle::Cast(type_error)->Get(message)->Equals(foo)); + CHECK(type_error.As()->Get(message)->Equals(foo)); v8::Handle error = v8::Exception::Error(foo); CHECK(error->IsObject()); - CHECK(v8::Handle::Cast(error)->Get(message)->Equals(foo)); + CHECK(error.As()->Get(message)->Equals(foo)); } @@ -4795,13 +4806,13 @@ static bool NamedAccessFlatten(Local global, CHECK(name->IsString()); memset(buf, 0x1, sizeof(buf)); - len = Local::Cast(name)->WriteAscii(buf); + len = name.As()->WriteAscii(buf); CHECK_EQ(4, len); uint16_t buf2[100]; memset(buf, 0x1, sizeof(buf)); - len = Local::Cast(name)->Write(buf2); + len = name.As()->Write(buf2); CHECK_EQ(4, len); return true; @@ -5150,7 +5161,7 @@ THREADED_TEST(HiddenPrototype) { // object. Local proto = o0->Get(v8_str("__proto__")); CHECK(proto->IsObject()); - CHECK(Local::Cast(proto)->Get(v8_str("z"))->IsUndefined()); + CHECK(proto.As()->Get(v8_str("z"))->IsUndefined()); } @@ -5194,20 +5205,20 @@ THREADED_TEST(SetPrototype) { // object. Local proto = o0->Get(v8_str("__proto__")); CHECK(proto->IsObject()); - CHECK_EQ(v8::Handle::Cast(proto), o3); + CHECK_EQ(proto.As(), o3); // However, Object::GetPrototype ignores hidden prototype. Local proto0 = o0->GetPrototype(); CHECK(proto0->IsObject()); - CHECK_EQ(v8::Handle::Cast(proto0), o1); + CHECK_EQ(proto0.As(), o1); Local proto1 = o1->GetPrototype(); CHECK(proto1->IsObject()); - CHECK_EQ(v8::Handle::Cast(proto1), o2); + CHECK_EQ(proto1.As(), o2); Local proto2 = o2->GetPrototype(); CHECK(proto2->IsObject()); - CHECK_EQ(v8::Handle::Cast(proto2), o3); + CHECK_EQ(proto2.As(), o3); } @@ -6919,7 +6930,7 @@ THREADED_TEST(ObjectProtoToString) { // Check ordinary object Local object = v8_compile("new Object()")->Run(); - value = Local::Cast(object)->ObjectProtoToString(); + value = object.As()->ObjectProtoToString(); CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); } @@ -7539,12 +7550,12 @@ THREADED_TEST(DateAccess) { LocalContext context; v8::Handle date = v8::Date::New(1224744689038.0); CHECK(date->IsDate()); - CHECK_EQ(1224744689038.0, v8::Handle::Cast(date)->NumberValue()); + CHECK_EQ(1224744689038.0, date.As()->NumberValue()); } void CheckProperties(v8::Handle val, int elmc, const char* elmv[]) { - v8::Handle obj = v8::Handle::Cast(val); + v8::Handle obj = val.As(); v8::Handle 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 elms = v8::Handle::Cast(obj); + v8::Handle elms = obj.As(); CHECK_EQ(4, elms->Length()); int elmc0 = 0; const char** elmv0 = NULL; @@ -8088,7 +8099,7 @@ TEST(ObjectClone) { // Create an object, verify basics. Local val = CompileRun(sample); CHECK(val->IsObject()); - Local obj = Local::Cast(val); + Local obj = val.As(); obj->Set(v8_str("gamma"), v8_str("cloneme")); CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); -- 2.7.4