summaryrefslogtreecommitdiff
path: root/chromium/gin
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/gin
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
downloadqtwebengine-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.gn2
-rw-r--r--chromium/gin/arguments_unittest.cc14
-rw-r--r--chromium/gin/context_holder.cc1
-rw-r--r--chromium/gin/converter.h35
-rw-r--r--chromium/gin/converter_unittest.cc5
-rw-r--r--chromium/gin/data_object_builder_unittest.cc2
-rw-r--r--chromium/gin/function_template.cc26
-rw-r--r--chromium/gin/function_template.h72
-rw-r--r--chromium/gin/gin_features.cc13
-rw-r--r--chromium/gin/gin_features.h17
-rw-r--r--chromium/gin/interceptor_unittest.cc3
-rw-r--r--chromium/gin/object_template_builder.cc8
-rw-r--r--chromium/gin/object_template_builder.h44
-rw-r--r--chromium/gin/shell/gin_main.cc2
-rw-r--r--chromium/gin/v8_initializer.cc33
-rw-r--r--chromium/gin/v8_initializer.h4
-rw-r--r--chromium/gin/wrappable.cc6
-rw-r--r--chromium/gin/wrappable.h4
-rw-r--r--chromium/gin/wrappable_unittest.cc154
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