diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:20:33 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:28:57 +0000 |
commit | d17ea114e5ef69ad5d5d7413280a13e6428098aa (patch) | |
tree | 2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/gin | |
parent | 8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff) | |
download | qtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz |
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/gin')
-rw-r--r-- | chromium/gin/BUILD.gn | 2 | ||||
-rw-r--r-- | chromium/gin/arguments_unittest.cc | 14 | ||||
-rw-r--r-- | chromium/gin/context_holder.cc | 1 | ||||
-rw-r--r-- | chromium/gin/converter.h | 35 | ||||
-rw-r--r-- | chromium/gin/converter_unittest.cc | 5 | ||||
-rw-r--r-- | chromium/gin/data_object_builder_unittest.cc | 2 | ||||
-rw-r--r-- | chromium/gin/function_template.cc | 26 | ||||
-rw-r--r-- | chromium/gin/function_template.h | 72 | ||||
-rw-r--r-- | chromium/gin/gin_features.cc | 13 | ||||
-rw-r--r-- | chromium/gin/gin_features.h | 17 | ||||
-rw-r--r-- | chromium/gin/interceptor_unittest.cc | 3 | ||||
-rw-r--r-- | chromium/gin/object_template_builder.cc | 8 | ||||
-rw-r--r-- | chromium/gin/object_template_builder.h | 44 | ||||
-rw-r--r-- | chromium/gin/shell/gin_main.cc | 2 | ||||
-rw-r--r-- | chromium/gin/v8_initializer.cc | 33 | ||||
-rw-r--r-- | chromium/gin/v8_initializer.h | 4 | ||||
-rw-r--r-- | chromium/gin/wrappable.cc | 6 | ||||
-rw-r--r-- | chromium/gin/wrappable.h | 4 | ||||
-rw-r--r-- | chromium/gin/wrappable_unittest.cc | 154 |
19 files changed, 359 insertions, 86 deletions
diff --git a/chromium/gin/BUILD.gn b/chromium/gin/BUILD.gn index 2684e608fcb..0301ac24a15 100644 --- a/chromium/gin/BUILD.gn +++ b/chromium/gin/BUILD.gn @@ -25,6 +25,8 @@ component("gin") { "function_template.cc", "function_template.h", "gin_export.h", + "gin_features.cc", + "gin_features.h", "handle.h", "interceptor.cc", "interceptor.h", diff --git a/chromium/gin/arguments_unittest.cc b/chromium/gin/arguments_unittest.cc index 6b6809a5f74..f1506ddba10 100644 --- a/chromium/gin/arguments_unittest.cc +++ b/chromium/gin/arguments_unittest.cc @@ -31,8 +31,9 @@ TEST_F(ArgumentsTest, TestArgumentsHolderCreationContext) { // |creation_context|. v8::Local<v8::ObjectTemplate> object_template = ObjectTemplateBuilder(isolate) - .SetMethod("checkCreationContext", - base::Bind(check_creation_context, creation_context)) + .SetMethod( + "checkCreationContext", + base::BindRepeating(check_creation_context, creation_context)) .Build(); v8::Local<v8::Object> object = @@ -100,9 +101,12 @@ TEST_F(ArgumentsTest, TestGetAll) { // |creation_context|. v8::Local<v8::ObjectTemplate> object_template = ObjectTemplateBuilder(isolate) - .SetMethod("check1", base::Bind(check_arguments, &list1, &called1)) - .SetMethod("check2", base::Bind(check_arguments, &list2, &called2)) - .SetMethod("check3", base::Bind(check_arguments, &list3, &called3)) + .SetMethod("check1", + base::BindRepeating(check_arguments, &list1, &called1)) + .SetMethod("check2", + base::BindRepeating(check_arguments, &list2, &called2)) + .SetMethod("check3", + base::BindRepeating(check_arguments, &list3, &called3)) .Build(); v8::Local<v8::Object> object = diff --git a/chromium/gin/context_holder.cc b/chromium/gin/context_holder.cc index a72250c865b..346256fd94e 100644 --- a/chromium/gin/context_holder.cc +++ b/chromium/gin/context_holder.cc @@ -21,6 +21,7 @@ ContextHolder::~ContextHolder() { void ContextHolder::SetContext(v8::Local<v8::Context> context) { DCHECK(context_.IsEmpty()); context_.Reset(isolate_, context); + context_.AnnotateStrongRetainer("gin::ContextHolder::context_"); data_.reset(new PerContextData(this, context)); } diff --git a/chromium/gin/converter.h b/chromium/gin/converter.h index c47ec0af000..38c1f7fc1d1 100644 --- a/chromium/gin/converter.h +++ b/chromium/gin/converter.h @@ -224,36 +224,17 @@ ConvertToV8(v8::Isolate* isolate, T input) { return Converter<T>::ToV8(isolate, input); } -template<typename T, bool = ToV8ReturnsMaybe<T>::value> struct ToV8Traits; - template <typename T> -struct ToV8Traits<T, true> { - static bool TryConvertToV8(v8::Isolate* isolate, - T input, - v8::Local<v8::Value>* output) { - auto maybe = ConvertToV8(isolate->GetCurrentContext(), input); - if (maybe.IsEmpty()) - return false; - *output = maybe.ToLocalChecked(); - return true; - } -}; - -template <typename T> -struct ToV8Traits<T, false> { - static bool TryConvertToV8(v8::Isolate* isolate, - T input, - v8::Local<v8::Value>* output) { - *output = ConvertToV8(isolate, input); - return true; - } -}; +std::enable_if_t<ToV8ReturnsMaybe<T>::value, bool> +TryConvertToV8(v8::Isolate* isolate, T input, v8::Local<v8::Value>* output) { + return ConvertToV8(isolate, input).ToLocal(output); +} template <typename T> -bool TryConvertToV8(v8::Isolate* isolate, - T input, - v8::Local<v8::Value>* output) { - return ToV8Traits<T>::TryConvertToV8(isolate, input, output); +std::enable_if_t<!ToV8ReturnsMaybe<T>::value, bool> +TryConvertToV8(v8::Isolate* isolate, T input, v8::Local<v8::Value>* output) { + *output = ConvertToV8(isolate, input); + return true; } // This crashes when input.size() > v8::String::kMaxLength. diff --git a/chromium/gin/converter_unittest.cc b/chromium/gin/converter_unittest.cc index 967ca13423f..ee486206448 100644 --- a/chromium/gin/converter_unittest.cc +++ b/chromium/gin/converter_unittest.cc @@ -167,10 +167,15 @@ TEST_F(ConverterTest, VectorOfWrappables) { v8::MaybeLocal<v8::Value> maybe = ConvertToV8(isolate, vector); v8::Local<v8::Value> array; ASSERT_TRUE(maybe.ToLocal(&array)); + v8::Local<v8::Value> array2; + ASSERT_TRUE(TryConvertToV8(isolate, vector, &array2)); std::vector<MyObject*> out_value; ASSERT_TRUE(ConvertFromV8(isolate, array, &out_value)); EXPECT_THAT(out_value, testing::ContainerEq(vector)); + std::vector<MyObject*> out_value2; + ASSERT_TRUE(ConvertFromV8(isolate, array2, &out_value2)); + EXPECT_THAT(out_value2, testing::ContainerEq(vector)); } } // namespace gin diff --git a/chromium/gin/data_object_builder_unittest.cc b/chromium/gin/data_object_builder_unittest.cc index 98db990f0c2..758b1191c93 100644 --- a/chromium/gin/data_object_builder_unittest.cc +++ b/chromium/gin/data_object_builder_unittest.cc @@ -90,7 +90,7 @@ TEST_F(DataObjectBuilderTest, UnusableAfterBuild) { EXPECT_FALSE(builder.Build().IsEmpty()); bool has_dcheck_failure = false; - logging::ScopedLogAssertHandler handler(base::Bind( + logging::ScopedLogAssertHandler handler(base::BindRepeating( [](bool* flag, const char* file, int line, base::StringPiece message, base::StringPiece stack_trace) { *flag = true; }, base::Unretained(&has_dcheck_failure))); diff --git a/chromium/gin/function_template.cc b/chromium/gin/function_template.cc index 46285f92068..cfce6ed09a7 100644 --- a/chromium/gin/function_template.cc +++ b/chromium/gin/function_template.cc @@ -4,6 +4,8 @@ #include "gin/function_template.h" +#include "base/strings/strcat.h" + namespace gin { namespace internal { @@ -35,6 +37,30 @@ void CallbackHolderBase::SecondWeakCallback( delete data.GetParameter(); } +void ThrowConversionError(Arguments* args, + const InvokerOptions& invoker_options, + size_t index) { + if (index == 0 && invoker_options.holder_is_first_argument) { + // Failed to get the appropriate `this` object. This can happen if a + // method is invoked using Function.prototype.[call|apply] and passed an + // invalid (or null) `this` argument. + std::string error = + invoker_options.holder_type + ? base::StrCat({"Illegal invocation: Function must be " + "called on an object of type ", + invoker_options.holder_type}) + : "Illegal invocation"; + args->ThrowTypeError(error); + } else { + // Otherwise, this failed parsing on a different argument. + // Arguments::ThrowError() will try to include appropriate information. + // Ideally we would include the expected c++ type in the error message + // here, too (which we can access via typeid(ArgType).name()), however we + // compile with no-rtti, which disables typeid. + args->ThrowError(); + } +} + } // namespace internal } // namespace gin diff --git a/chromium/gin/function_template.h b/chromium/gin/function_template.h index 1e60649a091..d94acc86bee 100644 --- a/chromium/gin/function_template.h +++ b/chromium/gin/function_template.h @@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/logging.h" #include "base/macros.h" +#include "base/strings/strcat.h" #include "gin/arguments.h" #include "gin/converter.h" #include "gin/gin_export.h" @@ -17,8 +18,9 @@ namespace gin { -enum CreateFunctionTemplateFlags { - HolderIsFirstArgument = 1 << 0, +struct InvokerOptions { + bool holder_is_first_argument = false; + const char* holder_type = nullptr; // Null if unknown or not applicable. }; namespace internal { @@ -66,22 +68,26 @@ class CallbackHolder : public CallbackHolderBase { public: CallbackHolder(v8::Isolate* isolate, base::RepeatingCallback<Sig> callback, - int flags) + InvokerOptions invoker_options) : CallbackHolderBase(isolate), callback(std::move(callback)), - flags(flags) {} + invoker_options(std::move(invoker_options)) {} + base::RepeatingCallback<Sig> callback; - int flags; + InvokerOptions invoker_options; + private: virtual ~CallbackHolder() {} DISALLOW_COPY_AND_ASSIGN(CallbackHolder); }; -template<typename T> -bool GetNextArgument(Arguments* args, int create_flags, bool is_first, +template <typename T> +bool GetNextArgument(Arguments* args, + const InvokerOptions& invoker_options, + bool is_first, T* result) { - if (is_first && (create_flags & HolderIsFirstArgument) != 0) { + if (is_first && invoker_options.holder_is_first_argument) { return args->GetHolder(result); } else { return args->GetNext(result); @@ -90,24 +96,35 @@ bool GetNextArgument(Arguments* args, int create_flags, bool is_first, // For advanced use cases, we allow callers to request the unparsed Arguments // object and poke around in it directly. -inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, +inline bool GetNextArgument(Arguments* args, + const InvokerOptions& invoker_options, + bool is_first, Arguments* result) { *result = *args; return true; } -inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, +inline bool GetNextArgument(Arguments* args, + const InvokerOptions& invoker_options, + bool is_first, Arguments** result) { *result = args; return true; } // It's common for clients to just need the isolate, so we make that easy. -inline bool GetNextArgument(Arguments* args, int create_flags, - bool is_first, v8::Isolate** result) { +inline bool GetNextArgument(Arguments* args, + const InvokerOptions& invoker_options, + bool is_first, + v8::Isolate** result) { *result = args->isolate(); return true; } +// Throws an error indicating conversion failure. +GIN_EXPORT void ThrowConversionError(Arguments* args, + const InvokerOptions& invoker_options, + size_t index); + // Class template for extracting and storing single argument for callback // at position |index|. template <size_t index, typename ArgType> @@ -117,14 +134,10 @@ struct ArgumentHolder { ArgLocalType value; bool ok; - ArgumentHolder(Arguments* args, int create_flags) - : ok(GetNextArgument(args, create_flags, index == 0, &value)) { - if (!ok) { - // Ideally we would include the expected c++ type in the error - // message which we can access via typeid(ArgType).name() - // however we compile with no-rtti, which disables typeid. - args->ThrowError(); - } + ArgumentHolder(Arguments* args, const InvokerOptions& invoker_options) + : ok(GetNextArgument(args, invoker_options, index == 0, &value)) { + if (!ok) + ThrowConversionError(args, invoker_options, index); } }; @@ -141,9 +154,9 @@ class Invoker<std::index_sequence<indices...>, ArgTypes...> // C++ has always been strict about the class initialization order, // so it is guaranteed ArgumentHolders will be initialized (and thus, will // extract arguments from Arguments) in the right order. - Invoker(Arguments* args, int create_flags) - : ArgumentHolder<indices, ArgTypes>(args, create_flags)..., args_(args) { - } + Invoker(Arguments* args, const InvokerOptions& invoker_options) + : ArgumentHolder<indices, ArgTypes>(args, invoker_options)..., + args_(args) {} bool IsOK() { return And(ArgumentHolder<indices, ArgTypes>::ok...); @@ -191,7 +204,7 @@ struct Dispatcher<ReturnType(ArgTypes...)> { HolderT* holder = static_cast<HolderT*>(holder_base); using Indices = std::index_sequence_for<ArgTypes...>; - Invoker<Indices, ArgTypes...> invoker(&args, holder->flags); + Invoker<Indices, ArgTypes...> invoker(&args, holder->invoker_options); if (invoker.IsOK()) invoker.DispatchToCallback(holder->callback); } @@ -199,11 +212,13 @@ struct Dispatcher<ReturnType(ArgTypes...)> { } // namespace internal - // CreateFunctionTemplate creates a v8::FunctionTemplate that will create // JavaScript functions that execute a provided C++ function or base::Callback. // JavaScript arguments are automatically converted via gin::Converter, as is -// the return value of the C++ function, if any. +// the return value of the C++ function, if any. |invoker_options| contains +// additional parameters. If it contains a holder_type, it will be used to +// provide a useful conversion error if the holder is the first argument. If not +// provided, a generic invocation error will be used. // // NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own // internal reasons, thus it is generally a good idea to cache the template @@ -213,9 +228,10 @@ template <typename Sig> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( v8::Isolate* isolate, base::RepeatingCallback<Sig> callback, - int callback_flags = 0) { + InvokerOptions invoker_options = {}) { typedef internal::CallbackHolder<Sig> HolderT; - HolderT* holder = new HolderT(isolate, std::move(callback), callback_flags); + HolderT* holder = + new HolderT(isolate, std::move(callback), std::move(invoker_options)); v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New( isolate, &internal::Dispatcher<Sig>::DispatchToCallback, diff --git a/chromium/gin/gin_features.cc b/chromium/gin/gin_features.cc new file mode 100644 index 00000000000..a487e256be9 --- /dev/null +++ b/chromium/gin/gin_features.cc @@ -0,0 +1,13 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/gin_features.h" + +namespace features { + +// Enables optimization of JavaScript in V8. +const base::Feature kV8OptimizeJavascript{"V8OptimizeJavascript", + base::FEATURE_ENABLED_BY_DEFAULT}; + +} // namespace features diff --git a/chromium/gin/gin_features.h b/chromium/gin/gin_features.h new file mode 100644 index 00000000000..58bb433c21a --- /dev/null +++ b/chromium/gin/gin_features.h @@ -0,0 +1,17 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_GIN_FEATURES_H_ +#define GIN_GIN_FEATURES_H_ + +#include "base/feature_list.h" +#include "gin/gin_export.h" + +namespace features { + +GIN_EXPORT extern const base::Feature kV8OptimizeJavascript; + +} // namespace features + +#endif // GIN_GIN_FEATURES_H_ diff --git a/chromium/gin/interceptor_unittest.cc b/chromium/gin/interceptor_unittest.cc index c085702743b..4af449f961b 100644 --- a/chromium/gin/interceptor_unittest.cc +++ b/chromium/gin/interceptor_unittest.cc @@ -114,7 +114,8 @@ class MyInterceptor : public Wrappable<MyInterceptor>, if (!function_template.IsEmpty()) return function_template; function_template = CreateFunctionTemplate( - isolate, base::Bind(&MyInterceptor::Call), HolderIsFirstArgument); + isolate, base::BindRepeating(&MyInterceptor::Call), + InvokerOptions{true, nullptr}); template_cache_.Set(name, function_template); return function_template; } diff --git a/chromium/gin/object_template_builder.cc b/chromium/gin/object_template_builder.cc index 53ff01ba41a..83abe42a1c5 100644 --- a/chromium/gin/object_template_builder.cc +++ b/chromium/gin/object_template_builder.cc @@ -141,7 +141,13 @@ void IndexedPropertyEnumerator( } // namespace ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate) - : isolate_(isolate), template_(v8::ObjectTemplate::New(isolate)) { + : ObjectTemplateBuilder(isolate, nullptr) {} + +ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate, + const char* type_name) + : isolate_(isolate), + type_name_(type_name), + template_(v8::ObjectTemplate::New(isolate)) { template_->SetInternalFieldCount(kNumberOfInternalFields); } diff --git a/chromium/gin/object_template_builder.h b/chromium/gin/object_template_builder.h index 92230ea06d3..2d67bb8e65e 100644 --- a/chromium/gin/object_template_builder.h +++ b/chromium/gin/object_template_builder.h @@ -17,21 +17,27 @@ namespace gin { +namespace internal { + template <typename T> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(v8::Isolate* isolate, - T callback) { + T callback, + const char* type_name) { // We need to handle member function pointers case specially because the first // parameter for callbacks to MFP should typically come from the the // JavaScript "this" object the function was called on, not from the first // normal parameter. - int callback_flags = 0; - if (std::is_member_function_pointer<T>::value) - callback_flags = HolderIsFirstArgument; - - return CreateFunctionTemplate( - isolate, base::BindRepeating(std::move(callback)), callback_flags); + InvokerOptions options; + if (std::is_member_function_pointer<T>::value) { + options.holder_is_first_argument = true; + options.holder_type = type_name; + } + return ::gin::CreateFunctionTemplate( + isolate, base::BindRepeating(std::move(callback)), std::move(options)); } +} // namespace internal + template <typename T> void SetAsFunctionHandler(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> tmpl, @@ -40,12 +46,10 @@ void SetAsFunctionHandler(v8::Isolate* isolate, // parameter for callbacks to MFP should typically come from the the // JavaScript "this" object the function was called on, not from the first // normal parameter. - int callback_flags = 0; - if (std::is_member_function_pointer<T>::value) - callback_flags = HolderIsFirstArgument; + InvokerOptions options = {std::is_member_function_pointer<T>::value, nullptr}; CreateFunctionHandler(isolate, tmpl, base::BindRepeating(std::move(callback)), - callback_flags); + std::move(options)); } // ObjectTemplateBuilder provides a handy interface to creating @@ -53,6 +57,7 @@ void SetAsFunctionHandler(v8::Isolate* isolate, class GIN_EXPORT ObjectTemplateBuilder { public: explicit ObjectTemplateBuilder(v8::Isolate* isolate); + ObjectTemplateBuilder(v8::Isolate* isolate, const char* type_name); ObjectTemplateBuilder(const ObjectTemplateBuilder& other); ~ObjectTemplateBuilder(); @@ -71,19 +76,22 @@ class GIN_EXPORT ObjectTemplateBuilder { template<typename T> ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, const T& callback) { - return SetImpl(name, CreateFunctionTemplate(isolate_, callback)); + return SetImpl( + name, internal::CreateFunctionTemplate(isolate_, callback, type_name_)); } template<typename T> ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, const T& getter) { - return SetPropertyImpl(name, CreateFunctionTemplate(isolate_, getter), - v8::Local<v8::FunctionTemplate>()); + return SetPropertyImpl( + name, internal::CreateFunctionTemplate(isolate_, getter, type_name_), + v8::Local<v8::FunctionTemplate>()); } template<typename T, typename U> ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, const T& getter, const U& setter) { - return SetPropertyImpl(name, CreateFunctionTemplate(isolate_, getter), - CreateFunctionTemplate(isolate_, setter)); + return SetPropertyImpl( + name, internal::CreateFunctionTemplate(isolate_, getter, type_name_), + internal::CreateFunctionTemplate(isolate_, setter, type_name_)); } ObjectTemplateBuilder& AddNamedPropertyInterceptor(); ObjectTemplateBuilder& AddIndexedPropertyInterceptor(); @@ -99,6 +107,10 @@ class GIN_EXPORT ObjectTemplateBuilder { v8::Isolate* isolate_; + // If provided, |type_name_| will be used to give a user-friendly error + // message if a member function is invoked on the wrong type of object. + const char* type_name_ = nullptr; + // ObjectTemplateBuilder should only be used on the stack. v8::Local<v8::ObjectTemplate> template_; }; diff --git a/chromium/gin/shell/gin_main.cc b/chromium/gin/shell/gin_main.cc index 2340951f415..d5b769dfff3 100644 --- a/chromium/gin/shell/gin_main.cc +++ b/chromium/gin/shell/gin_main.cc @@ -102,7 +102,7 @@ int main(int argc, char** argv) { it != args.end(); ++it) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind(gin::Run, runner.GetWeakPtr(), base::FilePath(*it))); + base::BindOnce(gin::Run, runner.GetWeakPtr(), base::FilePath(*it))); } base::RunLoop().RunUntilIdle(); diff --git a/chromium/gin/v8_initializer.cc b/chromium/gin/v8_initializer.cc index 9e0df626b2a..02d4b1cd652 100644 --- a/chromium/gin/v8_initializer.cc +++ b/chromium/gin/v8_initializer.cc @@ -25,6 +25,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "build/build_config.h" +#include "gin/gin_features.h" #if defined(V8_USE_EXTERNAL_STARTUP_DATA) #if defined(OS_ANDROID) @@ -70,19 +71,23 @@ base::LazyInstance<OpenedFileMap>::Leaky g_opened_files = LAZY_INSTANCE_INITIALIZER; const char kNativesFileName[] = "natives_blob.bin"; -const char kV8ContextSnapshotFileName[] = "v8_context_snapshot.bin"; #if defined(OS_ANDROID) +const char kV8ContextSnapshotFileName64[] = "v8_context_snapshot_64.bin"; +const char kV8ContextSnapshotFileName32[] = "v8_context_snapshot_32.bin"; const char kSnapshotFileName64[] = "snapshot_blob_64.bin"; const char kSnapshotFileName32[] = "snapshot_blob_32.bin"; #if defined(__LP64__) +#define kV8ContextSnapshotFileName kV8ContextSnapshotFileName64 #define kSnapshotFileName kSnapshotFileName64 #else +#define kV8ContextSnapshotFileName kV8ContextSnapshotFileName32 #define kSnapshotFileName kSnapshotFileName32 #endif #else // defined(OS_ANDROID) +const char kV8ContextSnapshotFileName[] = "v8_context_snapshot.bin"; const char kSnapshotFileName[] = "snapshot_blob.bin"; #endif // defined(OS_ANDROID) @@ -238,6 +243,14 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, v8::V8::InitializePlatform(V8Platform::Get()); + if (base::FeatureList::IsEnabled(features::kV8OptimizeJavascript)) { + static const char optimize[] = "--opt"; + v8::V8::SetFlagsFromString(optimize, sizeof(optimize) - 1); + } else { + static const char no_optimize[] = "--no-opt"; + v8::V8::SetFlagsFromString(no_optimize, sizeof(no_optimize) - 1); + } + if (IsolateHolder::kStrictMode == mode) { static const char use_strict[] = "--use_strict"; v8::V8::SetFlagsFromString(use_strict, sizeof(use_strict) - 1); @@ -380,9 +393,23 @@ base::FilePath V8Initializer::GetNativesFilePath() { } // static -base::FilePath V8Initializer::GetSnapshotFilePath(bool abi_32_bit) { +base::FilePath V8Initializer::GetSnapshotFilePath( + bool abi_32_bit, + V8SnapshotFileType snapshot_file_type) { base::FilePath path; - GetV8FilePath(abi_32_bit ? kSnapshotFileName32 : kSnapshotFileName64, &path); + const char* filename = nullptr; + switch (snapshot_file_type) { + case V8Initializer::V8SnapshotFileType::kDefault: + filename = abi_32_bit ? kSnapshotFileName32 : kSnapshotFileName64; + break; + case V8Initializer::V8SnapshotFileType::kWithAdditionalContext: + filename = abi_32_bit ? kV8ContextSnapshotFileName32 + : kV8ContextSnapshotFileName64; + break; + } + CHECK(filename); + + GetV8FilePath(filename, &path); return path; } #endif // defined(OS_ANDROID) diff --git a/chromium/gin/v8_initializer.h b/chromium/gin/v8_initializer.h index e427c213e42..6f3265ba4d0 100644 --- a/chromium/gin/v8_initializer.h +++ b/chromium/gin/v8_initializer.h @@ -67,7 +67,9 @@ class GIN_EXPORT V8Initializer { #if defined(OS_ANDROID) static base::FilePath GetNativesFilePath(); - static base::FilePath GetSnapshotFilePath(bool abi_32_bit); + static base::FilePath GetSnapshotFilePath( + bool abi_32_bit, + V8SnapshotFileType snapshot_file_type); #endif #endif // V8_USE_EXTERNAL_STARTUP_DATA diff --git a/chromium/gin/wrappable.cc b/chromium/gin/wrappable.cc index 22033bea6b8..258dc635027 100644 --- a/chromium/gin/wrappable.cc +++ b/chromium/gin/wrappable.cc @@ -18,7 +18,11 @@ WrappableBase::~WrappableBase() { ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder( v8::Isolate* isolate) { - return ObjectTemplateBuilder(isolate); + return ObjectTemplateBuilder(isolate, GetTypeName()); +} + +const char* WrappableBase::GetTypeName() { + return nullptr; } void WrappableBase::FirstWeakCallback( diff --git a/chromium/gin/wrappable.h b/chromium/gin/wrappable.h index 46da9a57143..88fb3c08723 100644 --- a/chromium/gin/wrappable.h +++ b/chromium/gin/wrappable.h @@ -70,6 +70,10 @@ class GIN_EXPORT WrappableBase { // Overrides of this method should be declared final and not overridden again. virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate); + // Returns a readable type name that will be used in surfacing errors. The + // default implementation returns nullptr, which results in a generic error. + virtual const char* GetTypeName(); + v8::MaybeLocal<v8::Object> GetWrapperImpl(v8::Isolate* isolate, WrapperInfo* wrapper_info); diff --git a/chromium/gin/wrappable_unittest.cc b/chromium/gin/wrappable_unittest.cc index 6a1cb450afa..716c89edfc3 100644 --- a/chromium/gin/wrappable_unittest.cc +++ b/chromium/gin/wrappable_unittest.cc @@ -16,6 +16,11 @@ namespace gin { +namespace { + +// A non-member function to be bound to an ObjectTemplateBuilder. +void NonMemberMethod() {} + // This useless base class ensures that the value of a pointer to a MyObject // (below) is not the same as the value of that pointer cast to the object's // WrappableBase base. @@ -45,16 +50,22 @@ class MyObject : public BaseClass, int value() const { return value_; } void set_value(int value) { value_ = value; } + void Method() {} + protected: MyObject() : value_(0) {} ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) final { return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate) - .SetProperty("value", &MyObject::value, &MyObject::set_value); + .SetProperty("value", &MyObject::value, &MyObject::set_value) + .SetMethod("memberMethod", &MyObject::Method) + .SetMethod("nonMemberMethod", &NonMemberMethod); } ~MyObject() override = default; private: int value_; + + DISALLOW_COPY_AND_ASSIGN(MyObject); }; class MyObject2 : public Wrappable<MyObject2> { @@ -62,8 +73,35 @@ class MyObject2 : public Wrappable<MyObject2> { static WrapperInfo kWrapperInfo; }; +class MyNamedObject : public Wrappable<MyNamedObject> { + public: + static WrapperInfo kWrapperInfo; + + static gin::Handle<MyNamedObject> Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new MyNamedObject()); + } + + void Method() {} + + protected: + MyNamedObject() = default; + ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) final { + return Wrappable<MyNamedObject>::GetObjectTemplateBuilder(isolate) + .SetMethod("memberMethod", &MyNamedObject::Method) + .SetMethod("nonMemberMethod", &NonMemberMethod); + } + const char* GetTypeName() final { return "MyNamedObject"; } + ~MyNamedObject() override = default; + + private: + DISALLOW_COPY_AND_ASSIGN(MyNamedObject); +}; + WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin }; WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin }; +WrapperInfo MyNamedObject::kWrapperInfo = {kEmbedderNativeGin}; + +} // namespace typedef V8Test WrappableTest; @@ -136,4 +174,118 @@ TEST_F(WrappableTest, GetAndSetProperty) { EXPECT_EQ(191, obj->value()); } +TEST_F(WrappableTest, MethodInvocationErrorsOnUnnamedObject) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = context_.Get(isolate); + + gin::Handle<MyObject> obj = MyObject::Create(isolate); + + v8::Local<v8::Object> v8_object = + ConvertToV8(isolate, obj.get()).ToLocalChecked().As<v8::Object>(); + v8::Local<v8::Value> member_method = + v8_object->Get(context, StringToV8(isolate, "memberMethod")) + .ToLocalChecked(); + ASSERT_TRUE(member_method->IsFunction()); + v8::Local<v8::Value> non_member_method = + v8_object->Get(context, StringToV8(isolate, "nonMemberMethod")) + .ToLocalChecked(); + ASSERT_TRUE(non_member_method->IsFunction()); + + auto get_error = [isolate, context](v8::Local<v8::Value> function_to_run, + v8::Local<v8::Value> context_object) { + constexpr char kScript[] = + "(function(toRun, contextObject) { toRun.apply(contextObject, []); })"; + v8::Local<v8::String> source = StringToV8(isolate, kScript); + EXPECT_FALSE(source.IsEmpty()); + + v8::TryCatch try_catch(isolate); + v8::Local<v8::Script> script = + v8::Script::Compile(context, source).ToLocalChecked(); + v8::Local<v8::Value> val = script->Run(context).ToLocalChecked(); + v8::Local<v8::Function> func; + EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); + v8::Local<v8::Value> argv[] = {function_to_run, context_object}; + func->Call(v8::Undefined(isolate), arraysize(argv), argv); + if (!try_catch.HasCaught()) + return std::string(); + return V8ToString(try_catch.Message()->Get()); + }; + + EXPECT_EQ(std::string(), get_error(member_method, v8_object)); + EXPECT_EQ(std::string(), get_error(non_member_method, v8_object)); + + EXPECT_EQ("Uncaught TypeError: Illegal invocation", + get_error(member_method, v8::Null(isolate))); + // A non-member function shouldn't throw errors for being applied on a + // null (or invalid) object. + EXPECT_EQ(std::string(), get_error(non_member_method, v8::Null(isolate))); + + v8::Local<v8::Object> wrong_object = v8::Object::New(isolate); + // We should get an error for passing the wrong object. + EXPECT_EQ("Uncaught TypeError: Illegal invocation", + get_error(member_method, wrong_object)); + // But again, not for a "static" method. + EXPECT_EQ(std::string(), get_error(non_member_method, v8::Null(isolate))); +} + +TEST_F(WrappableTest, MethodInvocationErrorsOnNamedObject) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = context_.Get(isolate); + + gin::Handle<MyNamedObject> obj = MyNamedObject::Create(isolate); + + v8::Local<v8::Object> v8_object = + ConvertToV8(isolate, obj.get()).ToLocalChecked().As<v8::Object>(); + v8::Local<v8::Value> member_method = + v8_object->Get(context, StringToV8(isolate, "memberMethod")) + .ToLocalChecked(); + ASSERT_TRUE(member_method->IsFunction()); + v8::Local<v8::Value> non_member_method = + v8_object->Get(context, StringToV8(isolate, "nonMemberMethod")) + .ToLocalChecked(); + ASSERT_TRUE(non_member_method->IsFunction()); + + auto get_error = [isolate, context](v8::Local<v8::Value> function_to_run, + v8::Local<v8::Value> context_object) { + constexpr char kScript[] = + "(function(toRun, contextObject) { toRun.apply(contextObject, []); })"; + v8::Local<v8::String> source = StringToV8(isolate, kScript); + EXPECT_FALSE(source.IsEmpty()); + + v8::TryCatch try_catch(isolate); + v8::Local<v8::Script> script = + v8::Script::Compile(context, source).ToLocalChecked(); + v8::Local<v8::Value> val = script->Run(context).ToLocalChecked(); + v8::Local<v8::Function> func; + EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); + v8::Local<v8::Value> argv[] = {function_to_run, context_object}; + func->Call(v8::Undefined(isolate), arraysize(argv), argv); + if (!try_catch.HasCaught()) + return std::string(); + return V8ToString(try_catch.Message()->Get()); + }; + + EXPECT_EQ(std::string(), get_error(member_method, v8_object)); + EXPECT_EQ(std::string(), get_error(non_member_method, v8_object)); + + EXPECT_EQ( + "Uncaught TypeError: Illegal invocation: Function must be called on " + "an object of type MyNamedObject", + get_error(member_method, v8::Null(isolate))); + // A non-member function shouldn't throw errors for being applied on a + // null (or invalid) object. + EXPECT_EQ(std::string(), get_error(non_member_method, v8::Null(isolate))); + + v8::Local<v8::Object> wrong_object = v8::Object::New(isolate); + // We should get an error for passing the wrong object. + EXPECT_EQ( + "Uncaught TypeError: Illegal invocation: Function must be called on " + "an object of type MyNamedObject", + get_error(member_method, wrong_object)); + // But again, not for a "static" method. + EXPECT_EQ(std::string(), get_error(non_member_method, v8::Null(isolate))); +} + } // namespace gin |