From 7a6acf6c7d45e24f07781c69249d90967013bbe4 Mon Sep 17 00:00:00 2001 From: bashi Date: Thu, 28 May 2015 21:06:05 -0700 Subject: [PATCH] gin: Use V8 Maybe APIs TEST=gin_unittests BUG=479439 Review URL: https://codereview.chromium.org/1106393002 Cr-Commit-Position: refs/heads/master@{#331923} --- gin/arguments.h | 5 ++- gin/converter.cc | 47 +++++++++++++++++--------- gin/converter.h | 77 +++++++++++++++++++++++++++++++++++++++--- gin/converter_unittest.cc | 17 ++++------ gin/dictionary.h | 14 ++++++-- gin/interceptor_unittest.cc | 2 +- gin/modules/console.cc | 2 +- gin/modules/module_registry.cc | 33 ++++++++++-------- gin/modules/module_registry.h | 6 ++-- gin/object_template_builder.cc | 14 +++++--- gin/shell/gin_main.cc | 4 ++- gin/shell_runner.cc | 25 ++++++++------ gin/test/file.cc | 6 ++-- gin/try_catch.cc | 16 +++++++-- gin/try_catch.h | 3 +- gin/wrappable.cc | 4 +-- gin/wrappable_unittest.cc | 8 ++--- 17 files changed, 204 insertions(+), 79 deletions(-) diff --git a/gin/arguments.h b/gin/arguments.h index 4ac38a7ef8f9..1affa2c8acb1 100644 --- a/gin/arguments.h +++ b/gin/arguments.h @@ -69,7 +69,10 @@ class GIN_EXPORT Arguments { template void Return(T val) { - info_->GetReturnValue().Set(ConvertToV8(isolate_, val)); + v8::Local v8_value; + if (!TryConvertToV8(isolate_, val, &v8_value)) + return; + info_->GetReturnValue().Set(v8_value); } v8::Local PeekNext() const; diff --git a/gin/converter.cc b/gin/converter.cc index d870bebc4bb8..9a3462d5a2dd 100644 --- a/gin/converter.cc +++ b/gin/converter.cc @@ -10,14 +10,30 @@ using v8::ArrayBuffer; using v8::Boolean; using v8::External; using v8::Function; +using v8::Int32; using v8::Integer; using v8::Isolate; using v8::Local; +using v8::Maybe; +using v8::MaybeLocal; using v8::Number; using v8::Object; using v8::String; +using v8::Uint32; using v8::Value; +namespace { + +template +bool FromMaybe(Maybe maybe, U* out) { + if (maybe.IsNothing()) + return false; + *out = static_cast(maybe.FromJust()); + return true; +} + +} // namespace + namespace gin { Local Converter::ToV8(Isolate* isolate, bool val) { @@ -25,8 +41,7 @@ Local Converter::ToV8(Isolate* isolate, bool val) { } bool Converter::FromV8(Isolate* isolate, Local val, bool* out) { - *out = val->BooleanValue(); - return true; + return FromMaybe(val->BooleanValue(isolate->GetCurrentContext()), out); } Local Converter::ToV8(Isolate* isolate, int32_t val) { @@ -38,7 +53,7 @@ bool Converter::FromV8(Isolate* isolate, int32_t* out) { if (!val->IsInt32()) return false; - *out = val->Int32Value(); + *out = val.As()->Value(); return true; } @@ -51,7 +66,7 @@ bool Converter::FromV8(Isolate* isolate, uint32_t* out) { if (!val->IsUint32()) return false; - *out = val->Uint32Value(); + *out = val.As()->Value(); return true; } @@ -66,8 +81,7 @@ bool Converter::FromV8(Isolate* isolate, return false; // Even though IntegerValue returns int64_t, JavaScript cannot represent // the full precision of int64_t, which means some rounding might occur. - *out = val->IntegerValue(); - return true; + return FromMaybe(val->IntegerValue(isolate->GetCurrentContext()), out); } Local Converter::ToV8(Isolate* isolate, uint64_t val) { @@ -79,8 +93,7 @@ bool Converter::FromV8(Isolate* isolate, uint64_t* out) { if (!val->IsNumber()) return false; - *out = static_cast(val->IntegerValue()); - return true; + return FromMaybe(val->IntegerValue(isolate->GetCurrentContext()), out); } Local Converter::ToV8(Isolate* isolate, float val) { @@ -90,7 +103,7 @@ Local Converter::ToV8(Isolate* isolate, float val) { bool Converter::FromV8(Isolate* isolate, Local val, float* out) { if (!val->IsNumber()) return false; - *out = static_cast(val->NumberValue()); + *out = static_cast(val.As()->Value()); return true; } @@ -103,14 +116,16 @@ bool Converter::FromV8(Isolate* isolate, double* out) { if (!val->IsNumber()) return false; - *out = val->NumberValue(); + *out = val.As()->Value(); return true; } Local Converter::ToV8(Isolate* isolate, const base::StringPiece& val) { - return String::NewFromUtf8(isolate, val.data(), String::kNormalString, - static_cast(val.length())); + return String::NewFromUtf8(isolate, val.data(), + v8::NewStringType::kNormal, + static_cast(val.length())) + .ToLocalChecked(); } Local Converter::ToV8(Isolate* isolate, @@ -194,10 +209,10 @@ bool Converter>::FromV8(Isolate* isolate, v8::Local StringToSymbol(v8::Isolate* isolate, const base::StringPiece& val) { - return String::NewFromUtf8(isolate, - val.data(), - String::kInternalizedString, - static_cast(val.length())); + return String::NewFromUtf8(isolate, val.data(), + v8::NewStringType::kInternalized, + static_cast(val.length())) + .ToLocalChecked(); } std::string V8ToString(v8::Local value) { diff --git a/gin/converter.h b/gin/converter.h index a07ada7effaa..8d17d41c29fb 100644 --- a/gin/converter.h +++ b/gin/converter.h @@ -8,12 +8,27 @@ #include #include +#include "base/logging.h" #include "base/strings/string_piece.h" #include "gin/gin_export.h" #include "v8/include/v8.h" namespace gin { +template +bool SetProperty(v8::Isolate* isolate, + v8::Local object, + KeyType key, + v8::Local value) { + auto maybe = object->Set(isolate->GetCurrentContext(), key, value); + return !maybe.IsNothing() && maybe.FromJust(); +} + +template +struct ToV8ReturnsMaybe { + static const bool value = false; +}; + template struct Converter {}; @@ -84,6 +99,7 @@ struct GIN_EXPORT Converter { template<> struct GIN_EXPORT Converter { + // This crashes when val.size() > v8::String::kMaxLength. static v8::Local ToV8(v8::Isolate* isolate, const base::StringPiece& val); // No conversion out is possible because StringPiece does not contain storage. @@ -91,6 +107,7 @@ struct GIN_EXPORT Converter { template<> struct GIN_EXPORT Converter { + // This crashes when val.size() > v8::String::kMaxLength. static v8::Local ToV8(v8::Isolate* isolate, const std::string& val); static bool FromV8(v8::Isolate* isolate, @@ -143,12 +160,15 @@ struct GIN_EXPORT Converter > { template struct Converter > { - static v8::Local ToV8(v8::Isolate* isolate, - const std::vector& val) { + static v8::MaybeLocal ToV8(v8::Local context, + const std::vector& val) { + v8::Isolate* isolate = context->GetIsolate(); v8::Local result( v8::Array::New(isolate, static_cast(val.size()))); - for (size_t i = 0; i < val.size(); ++i) { - result->Set(static_cast(i), Converter::ToV8(isolate, val[i])); + for (uint32_t i = 0; i < val.size(); ++i) { + auto maybe = result->Set(context, i, Converter::ToV8(isolate, val[i])); + if (maybe.IsNothing() || !maybe.FromJust()) + return v8::MaybeLocal(); } return result; } @@ -163,8 +183,11 @@ struct Converter > { v8::Local array(v8::Local::Cast(val)); uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++i) { + v8::Local v8_item; + if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item)) + return false; T item; - if (!Converter::FromV8(isolate, array->Get(i), &item)) + if (!Converter::FromV8(isolate, v8_item, &item)) return false; result.push_back(item); } @@ -174,18 +197,62 @@ struct Converter > { } }; +template +struct ToV8ReturnsMaybe> { + static const bool value = true; +}; + // Convenience functions that deduce T. template v8::Local ConvertToV8(v8::Isolate* isolate, T input) { return Converter::ToV8(isolate, input); } +template +v8::MaybeLocal ConvertToV8(v8::Local context, T input) { + return Converter::ToV8(context, input); +} + +template::value> struct ToV8Traits; + +template +struct ToV8Traits { + static bool TryConvertToV8(v8::Isolate* isolate, + T input, + v8::Local* output) { + auto maybe = ConvertToV8(isolate->GetCurrentContext(), input); + if (maybe.IsEmpty()) + return false; + *output = maybe.ToLocalChecked(); + return true; + } +}; + +template +struct ToV8Traits { + static bool TryConvertToV8(v8::Isolate* isolate, + T input, + v8::Local* output) { + *output = ConvertToV8(isolate, input); + return true; + } +}; + +template +bool TryConvertToV8(v8::Isolate* isolate, + T input, + v8::Local* output) { + return ToV8Traits::TryConvertToV8(isolate, input, output); +} + +// This crashes when input.size() > v8::String::kMaxLength. GIN_EXPORT inline v8::Local StringToV8( v8::Isolate* isolate, const base::StringPiece& input) { return ConvertToV8(isolate, input).As(); } +// This crashes when input.size() > v8::String::kMaxLength. GIN_EXPORT v8::Local StringToSymbol(v8::Isolate* isolate, const base::StringPiece& val); diff --git a/gin/converter_unittest.cc b/gin/converter_unittest.cc index 8b9adf414b05..a7c354703201 100644 --- a/gin/converter_unittest.cc +++ b/gin/converter_unittest.cc @@ -116,19 +116,16 @@ TEST_F(ConverterTest, Vector) { expected.push_back(0); expected.push_back(1); - Local js_array = Local::Cast( - Converter>::ToV8(instance_->isolate(), expected)); - ASSERT_FALSE(js_array.IsEmpty()); - EXPECT_EQ(3u, js_array->Length()); + auto maybe = Converter>::ToV8( + instance_->isolate()->GetCurrentContext(), expected); + Local js_value; + EXPECT_TRUE(maybe.ToLocal(&js_value)); + Local js_array2 = Local::Cast(js_value); + EXPECT_EQ(3u, js_array2->Length()); for (size_t i = 0; i < expected.size(); ++i) { EXPECT_TRUE(Integer::New(instance_->isolate(), expected[i]) - ->StrictEquals(js_array->Get(static_cast(i)))); + ->StrictEquals(js_array2->Get(static_cast(i)))); } - - std::vector actual; - EXPECT_TRUE(Converter >::FromV8(instance_->isolate(), - js_array, &actual)); - EXPECT_EQ(expected, actual); } } // namespace gin diff --git a/gin/dictionary.h b/gin/dictionary.h index efebfa85a702..64736b1d1625 100644 --- a/gin/dictionary.h +++ b/gin/dictionary.h @@ -32,13 +32,23 @@ class GIN_EXPORT Dictionary { template bool Get(const std::string& key, T* out) { - v8::Local val = object_->Get(StringToV8(isolate_, key)); + v8::Local val; + if (!object_->Get(isolate_->GetCurrentContext(), StringToV8(isolate_, key)) + .ToLocal(&val)) { + return false; + } return ConvertFromV8(isolate_, val, out); } template bool Set(const std::string& key, T val) { - return object_->Set(StringToV8(isolate_, key), ConvertToV8(isolate_, val)); + v8::Local v8_value; + if (!TryConvertToV8(isolate_, val, &v8_value)) + return false; + v8::Maybe result = + object_->Set(isolate_->GetCurrentContext(), StringToV8(isolate_, key), + v8_value); + return !result.IsNothing() && result.FromJust(); } v8::Isolate* isolate() const { return isolate_; } diff --git a/gin/interceptor_unittest.cc b/gin/interceptor_unittest.cc index 01c6ba950c54..02fb10d235a7 100644 --- a/gin/interceptor_unittest.cc +++ b/gin/interceptor_unittest.cc @@ -139,7 +139,7 @@ class InterceptorTest : public V8Test { v8::Local source = StringToV8(isolate, script_source); EXPECT_FALSE(source.IsEmpty()); - gin::TryCatch try_catch; + gin::TryCatch try_catch(isolate); v8::Local script = v8::Script::Compile(source); EXPECT_FALSE(script.IsEmpty()); v8::Local val = script->Run(); diff --git a/gin/modules/console.cc b/gin/modules/console.cc index d172373f01df..75241df081a7 100644 --- a/gin/modules/console.cc +++ b/gin/modules/console.cc @@ -43,7 +43,7 @@ v8::Local Console::GetModule(v8::Isolate* isolate) { .Build(); data->SetObjectTemplate(&g_wrapper_info, templ); } - return templ->NewInstance(); + return templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); } } // namespace gin diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc index 6c3e898cc29e..036e98df6bce 100644 --- a/gin/modules/module_registry.cc +++ b/gin/modules/module_registry.cc @@ -113,10 +113,14 @@ void ModuleRegistry::RegisterGlobals(Isolate* isolate, } // static -void ModuleRegistry::InstallGlobals(v8::Isolate* isolate, +bool ModuleRegistry::InstallGlobals(v8::Isolate* isolate, v8::Local obj) { - obj->Set(StringToSymbol(isolate, "define"), - GetDefineTemplate(isolate)->GetFunction()); + v8::Local function; + auto maybe_function = + GetDefineTemplate(isolate)->GetFunction(isolate->GetCurrentContext()); + if (!maybe_function.ToLocal(&function)) + return false; + return SetProperty(isolate, obj, StringToSymbol(isolate, "define"), function); } // static @@ -177,16 +181,17 @@ void ModuleRegistry::LoadModule(Isolate* isolate, unsatisfied_dependencies_.insert(id); } -void ModuleRegistry::RegisterModule(Isolate* isolate, +bool ModuleRegistry::RegisterModule(Isolate* isolate, const std::string& id, v8::Local module) { if (id.empty() || module.IsEmpty()) - return; + return false; + v8::Local modules = Local::New(isolate, modules_); + if (!SetProperty(isolate, modules, StringToSymbol(isolate, id), module)) + return false; unsatisfied_dependencies_.erase(id); available_modules_.insert(id); - v8::Local modules = Local::New(isolate, modules_); - modules->Set(StringToSymbol(isolate, id), module); std::pair range = waiting_callbacks_.equal_range(id); @@ -203,6 +208,7 @@ void ModuleRegistry::RegisterModule(Isolate* isolate, // Should we call the callback asynchronously? it->Run(module); } + return true; } bool ModuleRegistry::CheckDependencies(PendingModule* pending) { @@ -218,9 +224,9 @@ bool ModuleRegistry::CheckDependencies(PendingModule* pending) { return num_missing_dependencies == 0; } -void ModuleRegistry::Load(Isolate* isolate, scoped_ptr pending) { +bool ModuleRegistry::Load(Isolate* isolate, scoped_ptr pending) { if (!pending->id.empty() && available_modules_.count(pending->id)) - return; // We've already loaded this module. + return true; // We've already loaded this module. uint32_t argc = static_cast(pending->dependencies.size()); std::vector > argv(argc); @@ -240,7 +246,7 @@ void ModuleRegistry::Load(Isolate* isolate, scoped_ptr pending) { &pending->id); } - RegisterModule(isolate, pending->id, module); + return RegisterModule(isolate, pending->id, module); } bool ModuleRegistry::AttemptToLoad(Isolate* isolate, @@ -249,16 +255,15 @@ bool ModuleRegistry::AttemptToLoad(Isolate* isolate, pending_modules_.push_back(pending.release()); return false; } - Load(isolate, pending.Pass()); - return true; + return Load(isolate, pending.Pass()); } v8::Local ModuleRegistry::GetModule(v8::Isolate* isolate, const std::string& id) { v8::Local modules = Local::New(isolate, modules_); v8::Local key = StringToSymbol(isolate, id); - DCHECK(modules->HasOwnProperty(key)); - return modules->Get(key); + DCHECK(modules->HasOwnProperty(isolate->GetCurrentContext(), key).FromJust()); + return modules->Get(isolate->GetCurrentContext(), key).ToLocalChecked(); } void ModuleRegistry::AttemptToLoadMoreModules(Isolate* isolate) { diff --git a/gin/modules/module_registry.h b/gin/modules/module_registry.h index c53155a44a4c..b67387b2ac58 100644 --- a/gin/modules/module_registry.h +++ b/gin/modules/module_registry.h @@ -47,7 +47,7 @@ class GIN_EXPORT ModuleRegistry { // Installs the necessary functions needed for modules. // WARNING: this may execute script in the page. - static void InstallGlobals(v8::Isolate* isolate, v8::Local obj); + static bool InstallGlobals(v8::Isolate* isolate, v8::Local obj); void AddObserver(ModuleRegistryObserver* observer); void RemoveObserver(ModuleRegistryObserver* observer); @@ -81,8 +81,8 @@ class GIN_EXPORT ModuleRegistry { explicit ModuleRegistry(v8::Isolate* isolate); - void Load(v8::Isolate* isolate, scoped_ptr pending); - void RegisterModule(v8::Isolate* isolate, + bool Load(v8::Isolate* isolate, scoped_ptr pending); + bool RegisterModule(v8::Isolate* isolate, const std::string& id, v8::Local module); diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc index 264552f96630..28c9791b05fd 100644 --- a/gin/object_template_builder.cc +++ b/gin/object_template_builder.cc @@ -93,8 +93,11 @@ void NamedPropertyEnumerator(const v8::PropertyCallbackInfo& info) { NamedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) return; - info.GetReturnValue().Set(v8::Local::Cast( - ConvertToV8(isolate, interceptor->EnumerateNamedProperties(isolate)))); + v8::Local properties; + if (!TryConvertToV8(isolate, interceptor->EnumerateNamedProperties(isolate), + &properties)) + return; + info.GetReturnValue().Set(v8::Local::Cast(properties)); } void IndexedPropertyGetter(uint32_t index, @@ -126,8 +129,11 @@ void IndexedPropertyEnumerator( IndexedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) return; - info.GetReturnValue().Set(v8::Local::Cast( - ConvertToV8(isolate, interceptor->EnumerateIndexedProperties(isolate)))); + v8::Local properties; + if (!TryConvertToV8(isolate, interceptor->EnumerateIndexedProperties(isolate), + &properties)) + return; + info.GetReturnValue().Set(v8::Local::Cast(properties)); } } // namespace diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc index d3bab721bebd..62143c9926f5 100644 --- a/gin/shell/gin_main.cc +++ b/gin/shell/gin_main.cc @@ -75,7 +75,9 @@ int main(int argc, char** argv) { { gin::Runner::Scope scope(&runner); - v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); + runner.GetContextHolder() + ->isolate() + ->SetCaptureStackTraceForUncaughtExceptions(true); } base::CommandLine::StringVector args = diff --git a/gin/shell_runner.cc b/gin/shell_runner.cc index eccee9f69ca3..0e534e4af027 100644 --- a/gin/shell_runner.cc +++ b/gin/shell_runner.cc @@ -65,11 +65,13 @@ ShellRunner::~ShellRunner() { void ShellRunner::Run(const std::string& source, const std::string& resource_name) { - TryCatch try_catch; v8::Isolate* isolate = GetContextHolder()->isolate(); - v8::Local