summaryrefslogtreecommitdiffstats
path: root/chromium/gin
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/gin
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/gin')
-rw-r--r--chromium/gin/BUILD.gn125
-rw-r--r--chromium/gin/README26
-rw-r--r--chromium/gin/arguments.h11
-rw-r--r--chromium/gin/array_buffer.cc37
-rw-r--r--chromium/gin/array_buffer.h2
-rw-r--r--chromium/gin/context_holder.cc10
-rw-r--r--chromium/gin/converter.cc12
-rw-r--r--chromium/gin/converter.h12
-rw-r--r--chromium/gin/converter_unittest.cc5
-rw-r--r--chromium/gin/function_template.cc33
-rw-r--r--chromium/gin/function_template.h249
-rw-r--r--chromium/gin/function_template.h.pump83
-rw-r--r--chromium/gin/gin.gyp21
-rw-r--r--chromium/gin/handle.h5
-rw-r--r--chromium/gin/interceptor.cc64
-rw-r--r--chromium/gin/interceptor.h63
-rw-r--r--chromium/gin/interceptor_unittest.cc159
-rw-r--r--chromium/gin/isolate_holder.cc34
-rw-r--r--chromium/gin/modules/console.cc22
-rw-r--r--chromium/gin/modules/console.h2
-rw-r--r--chromium/gin/modules/file_module_provider.cc5
-rw-r--r--chromium/gin/modules/module_registry.cc73
-rw-r--r--chromium/gin/modules/module_registry.h24
-rw-r--r--chromium/gin/modules/module_registry_observer.h31
-rw-r--r--chromium/gin/modules/module_registry_unittest.cc99
-rw-r--r--chromium/gin/modules/module_runner_delegate.cc30
-rw-r--r--chromium/gin/modules/module_runner_delegate.h25
-rw-r--r--chromium/gin/modules/timer.cc103
-rw-r--r--chromium/gin/modules/timer.h64
-rw-r--r--chromium/gin/modules/timer_unittest.cc155
-rw-r--r--chromium/gin/object_template_builder.cc143
-rw-r--r--chromium/gin/object_template_builder.h23
-rw-r--r--chromium/gin/per_context_data.cc33
-rw-r--r--chromium/gin/per_context_data.h40
-rw-r--r--chromium/gin/per_context_data_unittest.cc34
-rw-r--r--chromium/gin/per_isolate_data.cc60
-rw-r--r--chromium/gin/per_isolate_data.h39
-rw-r--r--chromium/gin/public/context_holder.h6
-rw-r--r--chromium/gin/public/isolate_holder.h25
-rw-r--r--chromium/gin/public/v8_platform.h38
-rw-r--r--chromium/gin/runner.cc86
-rw-r--r--chromium/gin/runner.h51
-rw-r--r--chromium/gin/shell/gin_main.cc10
-rw-r--r--chromium/gin/shell_runner.cc112
-rw-r--r--chromium/gin/shell_runner.h68
-rw-r--r--chromium/gin/shell_runner_unittest.cc (renamed from chromium/gin/runner_unittest.cc)10
-rw-r--r--chromium/gin/v8_platform.cc42
-rw-r--r--chromium/gin/wrappable.cc31
-rw-r--r--chromium/gin/wrappable.h29
-rw-r--r--chromium/gin/wrappable_unittest.cc175
50 files changed, 2191 insertions, 448 deletions
diff --git a/chromium/gin/BUILD.gn b/chromium/gin/BUILD.gn
new file mode 100644
index 00000000000..7b3f06edf5d
--- /dev/null
+++ b/chromium/gin/BUILD.gn
@@ -0,0 +1,125 @@
+# Copyright 2014 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.
+
+component("gin") {
+ sources = [
+ "arguments.cc",
+ "arguments.h",
+ "array_buffer.cc",
+ "array_buffer.h",
+ "context_holder.cc",
+ "converter.cc",
+ "converter.h",
+ "dictionary.cc",
+ "dictionary.h",
+ "function_template.cc",
+ "function_template.h",
+ "gin_export.h",
+ "handle.h",
+ "interceptor.cc",
+ "interceptor.h",
+ "isolate_holder.cc",
+ "modules/console.cc",
+ "modules/console.h",
+ "modules/file_module_provider.cc",
+ "modules/file_module_provider.h",
+ "modules/module_registry.cc",
+ "modules/module_registry.h",
+ "modules/module_registry_observer.h",
+ "modules/module_runner_delegate.cc",
+ "modules/module_runner_delegate.h",
+ "modules/timer.cc",
+ "modules/timer.h",
+ "object_template_builder.cc",
+ "object_template_builder.h",
+ "per_context_data.cc",
+ "per_context_data.h",
+ "per_isolate_data.cc",
+ "per_isolate_data.h",
+ "public/context_holder.h",
+ "public/gin_embedders.h",
+ "public/isolate_holder.h",
+ "public/v8_platform.h",
+ "public/wrapper_info.h",
+ "runner.cc",
+ "runner.h",
+ "shell_runner.cc",
+ "shell_runner.h",
+ "try_catch.cc",
+ "try_catch.h",
+ "v8_platform.cc",
+ "wrappable.cc",
+ "wrappable.h",
+ "wrapper_info.cc",
+ ]
+
+ defines = [ "GIN_IMPLEMENTATION" ]
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//v8",
+ ]
+
+ forward_dependent_configs_from = [
+ "//base",
+ "//v8",
+ ]
+}
+
+executable("gin_shell") {
+ sources = [
+ "shell/gin_main.cc",
+ ]
+
+ deps = [
+ ":gin",
+ "//base",
+ "//base:i18n",
+ "//v8",
+ ]
+}
+
+source_set("gin_test") {
+ sources = [
+ "test/file_runner.cc",
+ "test/file_runner.h",
+ "test/gc.cc",
+ "test/gc.h",
+ "test/gtest.cc",
+ "test/gtest.h",
+ "test/v8_test.cc",
+ "test/v8_test.h",
+ ]
+
+ deps = [
+ ":gin",
+ "//testing/gtest",
+ "//v8",
+ ]
+
+ forward_dependent_configs_from = [
+ ":gin",
+ "//testing/gtest",
+ ]
+}
+
+test("gin_unittests") {
+ sources = [
+ "converter_unittest.cc",
+ "interceptor_unittest.cc",
+ "modules/module_registry_unittest.cc",
+ "modules/timer_unittest.cc",
+ "per_context_data_unittest.cc",
+ "shell_runner_unittest.cc",
+ "test/run_all_unittests.cc",
+ "test/run_js_tests.cc",
+ "wrappable_unittest.cc",
+ ]
+
+ deps = [
+ ":gin_test",
+ "//base/test:test_support",
+ "//v8",
+ ]
+}
diff --git a/chromium/gin/README b/chromium/gin/README
index 82d06188f3f..fc2d92e0f78 100644
--- a/chromium/gin/README
+++ b/chromium/gin/README
@@ -1,8 +1,24 @@
Gin - Lightweight bindings for V8
=================================
-This directory contains gin, a lightweight bindings library for V8. These
-bindings are not compatible with the V8 bindings used by Blink because both
-want to control the v8::Isolate's internal data field. Maybe in some future
-world we'll refactor the Blink V8 bindings to use this system. In the meantime,
-these bindings are convenient for projects other than Blink that use V8.
+This directory contains Gin, a set of utilities to make working with V8 easier.
+
+Here are some of the key bits:
+
+* converter.h: Templatized JS<->C++ conversion routines for many common C++
+ types. You can define your own by specializing Converter.
+
+* function_template.h: Create JavaScript functions that dispatch to any C++
+ function, member function pointer, or base::Callback.
+
+* object_template_builder.h: A handy utility for creation of v8::ObjectTemplate.
+
+* wrappable.h: Base class for C++ classes that want to be owned by the V8 GC.
+ Wrappable objects are automatically deleted when GC discovers that nothing in
+ the V8 heap refers to them. This is also an easy way to expose C++ objects to
+ JavaScript.
+
+* runner.h: Create script contexts and run code in them.
+
+* module_runner_delegate.h: A delegate for runner that implements a subset of
+ the AMD module specification. Also see modules/ with some example modules.
diff --git a/chromium/gin/arguments.h b/chromium/gin/arguments.h
index ec4ae80e882..509c22ca14f 100644
--- a/chromium/gin/arguments.h
+++ b/chromium/gin/arguments.h
@@ -56,6 +56,17 @@ class GIN_EXPORT Arguments {
return true;
}
+ bool Skip() {
+ if (next_ >= info_->Length())
+ return false;
+ next_++;
+ return true;
+ }
+
+ int Length() const {
+ return info_->Length();
+ }
+
template<typename T>
void Return(T val) {
info_->GetReturnValue().Set(ConvertToV8(isolate_, val));
diff --git a/chromium/gin/array_buffer.cc b/chromium/gin/array_buffer.cc
index ee9f2a5867b..b777402e644 100644
--- a/chromium/gin/array_buffer.cc
+++ b/chromium/gin/array_buffer.cc
@@ -2,17 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "gin/array_buffer.h"
-
#include <stdlib.h>
+#include "base/logging.h"
+#include "gin/array_buffer.h"
+#include "gin/per_isolate_data.h"
+
namespace gin {
+namespace {
+
+gin::WrapperInfo g_array_buffer_wrapper_info = {gin::kEmbedderNativeGin};
+
+} // namespace
+
COMPILE_ASSERT(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2,
array_buffers_must_have_two_internal_fields);
-static const int kBufferViewPrivateIndex = 0;
-
// ArrayBufferAllocator -------------------------------------------------------
void* ArrayBufferAllocator::Allocate(size_t length) {
@@ -72,6 +78,7 @@ class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> {
v8::Persistent<v8::ArrayBuffer> array_buffer_;
scoped_refptr<Private> self_reference_;
+ v8::Isolate* isolate_;
void* buffer_;
size_t length_;
};
@@ -79,28 +86,34 @@ class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> {
scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From(
v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) {
if (array->IsExternal()) {
+ CHECK_EQ(WrapperInfo::From(v8::Handle<v8::Object>::Cast(array)),
+ &g_array_buffer_wrapper_info)
+ << "Cannot mix blink and gin ArrayBuffers";
return make_scoped_refptr(static_cast<Private*>(
- array->GetAlignedPointerFromInternalField(kBufferViewPrivateIndex)));
+ array->GetAlignedPointerFromInternalField(kEncodedValueIndex)));
}
return make_scoped_refptr(new Private(isolate, array));
}
ArrayBuffer::Private::Private(v8::Isolate* isolate,
v8::Handle<v8::ArrayBuffer> array)
- : array_buffer_(isolate, array) {
+ : array_buffer_(isolate, array), isolate_(isolate) {
// Take ownership of the array buffer.
+ CHECK(!array->IsExternal());
v8::ArrayBuffer::Contents contents = array->Externalize();
buffer_ = contents.Data();
length_ = contents.ByteLength();
- array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this);
+ array->SetAlignedPointerInInternalField(kWrapperInfoIndex,
+ &g_array_buffer_wrapper_info);
+ array->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
self_reference_ = this; // Cleared in WeakCallback.
array_buffer_.SetWeak(this, WeakCallback);
}
ArrayBuffer::Private::~Private() {
- ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_);
+ PerIsolateData::From(isolate_)->allocator()->Free(buffer_, length_);
}
void ArrayBuffer::Private::WeakCallback(
@@ -162,6 +175,14 @@ ArrayBufferView::ArrayBufferView(v8::Isolate* isolate,
ArrayBufferView::~ArrayBufferView() {
}
+ArrayBufferView& ArrayBufferView::operator=(const ArrayBufferView& other) {
+ array_buffer_ = other.array_buffer_;
+ offset_ = other.offset_;
+ num_bytes_ = other.num_bytes_;
+ return *this;
+}
+
+
// Converter<ArrayBufferView> -------------------------------------------------
bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate,
diff --git a/chromium/gin/array_buffer.h b/chromium/gin/array_buffer.h
index 7886fa9be05..858cbf1088a 100644
--- a/chromium/gin/array_buffer.h
+++ b/chromium/gin/array_buffer.h
@@ -26,7 +26,6 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
class GIN_EXPORT ArrayBuffer {
public:
ArrayBuffer();
- explicit ArrayBuffer(v8::Isolate* isolate);
ArrayBuffer(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer);
~ArrayBuffer();
ArrayBuffer& operator=(const ArrayBuffer& other);
@@ -55,6 +54,7 @@ class GIN_EXPORT ArrayBufferView {
ArrayBufferView();
ArrayBufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBufferView> view);
~ArrayBufferView();
+ ArrayBufferView& operator=(const ArrayBufferView& other);
void* bytes() const {
return static_cast<uint8_t*>(array_buffer_.bytes()) + offset_;
diff --git a/chromium/gin/context_holder.cc b/chromium/gin/context_holder.cc
index 32b50518376..241b25622c5 100644
--- a/chromium/gin/context_holder.cc
+++ b/chromium/gin/context_holder.cc
@@ -14,20 +14,14 @@ ContextHolder::ContextHolder(v8::Isolate* isolate)
}
ContextHolder::~ContextHolder() {
- v8::HandleScope handle_scope(isolate());
- v8::Handle<v8::Context> context = this->context();
-
- data_->Detach(context);
+ // PerContextData needs to be destroyed before the context.
data_.reset();
-
- // TODO(abarth): Figure out how to set kResetInDestructor to true.
- context_.Reset();
}
void ContextHolder::SetContext(v8::Handle<v8::Context> context) {
DCHECK(context_.IsEmpty());
context_.Reset(isolate_, context);
- data_.reset(new PerContextData(context));
+ data_.reset(new PerContextData(this, context));
}
} // namespace gin
diff --git a/chromium/gin/converter.cc b/chromium/gin/converter.cc
index 54736f95aaf..07437b7edc2 100644
--- a/chromium/gin/converter.cc
+++ b/chromium/gin/converter.cc
@@ -79,6 +79,18 @@ bool Converter<uint64_t>::FromV8(Isolate* isolate, Handle<Value> val,
return true;
}
+Handle<Value> Converter<float>::ToV8(Isolate* isolate, float val) {
+ return Number::New(isolate, val).As<Value>();
+}
+
+bool Converter<float>::FromV8(Isolate* isolate, Handle<Value> val,
+ float* out) {
+ if (!val->IsNumber())
+ return false;
+ *out = static_cast<float>(val->NumberValue());
+ return true;
+}
+
Handle<Value> Converter<double>::ToV8(Isolate* isolate, double val) {
return Number::New(isolate, val).As<Value>();
}
diff --git a/chromium/gin/converter.h b/chromium/gin/converter.h
index ee029a7f770..e5c95fc1f9f 100644
--- a/chromium/gin/converter.h
+++ b/chromium/gin/converter.h
@@ -65,6 +65,15 @@ struct GIN_EXPORT Converter<uint64_t> {
};
template<>
+struct GIN_EXPORT Converter<float> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ float val);
+ static bool FromV8(v8::Isolate* isolate,
+ v8::Handle<v8::Value> val,
+ float* out);
+};
+
+template<>
struct GIN_EXPORT Converter<double> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
double val);
@@ -167,8 +176,7 @@ struct Converter<std::vector<T> > {
// Convenience functions that deduce T.
template<typename T>
-v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate,
- T input) {
+v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate, T input) {
return Converter<T>::ToV8(isolate, input);
}
diff --git a/chromium/gin/converter_unittest.cc b/chromium/gin/converter_unittest.cc
index 9b831b91ac0..791d7e66ec5 100644
--- a/chromium/gin/converter_unittest.cc
+++ b/chromium/gin/converter_unittest.cc
@@ -73,8 +73,9 @@ TEST_F(ConverterTest, Int32) {
int test_data_to[] = {-1, 0, 1};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data_to); ++i) {
- EXPECT_TRUE(Converter<int32_t>::ToV8(instance_->isolate(),
- test_data_to[i])->StrictEquals(Integer::New(test_data_to[i])));
+ EXPECT_TRUE(Converter<int32_t>::ToV8(instance_->isolate(), test_data_to[i])
+ ->StrictEquals(
+ Integer::New(instance_->isolate(), test_data_to[i])));
}
struct {
diff --git a/chromium/gin/function_template.cc b/chromium/gin/function_template.cc
index 5dd5ecd3d50..f76a05bea6b 100644
--- a/chromium/gin/function_template.cc
+++ b/chromium/gin/function_template.cc
@@ -4,23 +4,30 @@
#include "gin/function_template.h"
-#include "gin/per_isolate_data.h"
-
namespace gin {
-WrapperInfo internal::CallbackHolderBase::kWrapperInfo = { kEmbedderNativeGin };
+namespace internal {
+
+CallbackHolderBase::CallbackHolderBase(v8::Isolate* isolate)
+ : v8_ref_(isolate, v8::External::New(isolate, this)) {
+ v8_ref_.SetWeak(this, &CallbackHolderBase::WeakCallback);
+}
-void InitFunctionTemplates(PerIsolateData* isolate_data) {
- if (!isolate_data->GetObjectTemplate(
- &internal::CallbackHolderBase::kWrapperInfo).IsEmpty()) {
- return;
- }
+CallbackHolderBase::~CallbackHolderBase() {
+ DCHECK(v8_ref_.IsEmpty());
+}
- v8::Handle<v8::ObjectTemplate> templ(
- v8::ObjectTemplate::New(isolate_data->isolate()));
- templ->SetInternalFieldCount(kNumberOfInternalFields);
- isolate_data->SetObjectTemplate(&internal::CallbackHolderBase::kWrapperInfo,
- templ);
+v8::Handle<v8::External> CallbackHolderBase::GetHandle(v8::Isolate* isolate) {
+ return v8::Local<v8::External>::New(isolate, v8_ref_);
}
+// static
+void CallbackHolderBase::WeakCallback(
+ const v8::WeakCallbackData<v8::External, CallbackHolderBase>& data) {
+ data.GetParameter()->v8_ref_.Reset();
+ delete data.GetParameter();
+}
+
+} // namespace internal
+
} // namespace gin
diff --git a/chromium/gin/function_template.h b/chromium/gin/function_template.h
index 14f6e78fe2f..7ba54b5910e 100644
--- a/chromium/gin/function_template.h
+++ b/chromium/gin/function_template.h
@@ -16,11 +16,6 @@
#include "gin/arguments.h"
#include "gin/converter.h"
#include "gin/gin_export.h"
-#include "gin/handle.h"
-#include "gin/public/gin_embedders.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-
#include "v8/include/v8.h"
namespace gin {
@@ -50,31 +45,39 @@ struct CallbackParamTraits<const T*> {
// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from
// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
// DispatchToCallback, where it is invoked.
-//
-// v8::FunctionTemplate only supports passing void* as data so how do we know
-// when to delete the base::Callback? That's where CallbackHolderBase comes in.
-// It inherits from Wrappable, which delete itself when both (a) the refcount
-// via base::RefCounted has dropped to zero, and (b) there are no more
-// JavaScript references in V8.
// This simple base class is used so that we can share a single object template
// among every CallbackHolder instance.
-class GIN_EXPORT CallbackHolderBase : public Wrappable<CallbackHolderBase> {
+class GIN_EXPORT CallbackHolderBase {
public:
- static WrapperInfo kWrapperInfo;
+ v8::Handle<v8::External> GetHandle(v8::Isolate* isolate);
+
protected:
- virtual ~CallbackHolderBase() {}
+ explicit CallbackHolderBase(v8::Isolate* isolate);
+ virtual ~CallbackHolderBase();
+
+ private:
+ static void WeakCallback(
+ const v8::WeakCallbackData<v8::External, CallbackHolderBase>& data);
+
+ v8::Persistent<v8::External> v8_ref_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase);
};
template<typename Sig>
class CallbackHolder : public CallbackHolderBase {
public:
- CallbackHolder(const base::Callback<Sig>& callback, int flags)
- : callback(callback), flags(flags) {}
+ CallbackHolder(v8::Isolate* isolate,
+ const base::Callback<Sig>& callback,
+ int flags)
+ : CallbackHolderBase(isolate), callback(callback), flags(flags) {}
base::Callback<Sig> callback;
int flags;
private:
virtual ~CallbackHolder() {}
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
};
@@ -86,10 +89,69 @@ class CallbackHolder : public CallbackHolderBase {
// expression to foo. As a result, we must specialize the case of Callbacks that
// have the void return type.
template<typename R, typename P1 = void, typename P2 = void,
- typename P3 = void, typename P4 = void>
+ typename P3 = void, typename P4 = void, typename P5 = void,
+ typename P6 = void>
struct Invoker {
inline static void Go(
Arguments* args,
+ const base::Callback<R(P1, P2, P3, P4, P5, P6)>& callback,
+ const P1& a1,
+ const P2& a2,
+ const P3& a3,
+ const P4& a4,
+ const P5& a5,
+ const P6& a6) {
+ args->Return(callback.Run(a1, a2, a3, a4, a5, a6));
+ }
+};
+template<typename P1, typename P2, typename P3, typename P4, typename P5,
+ typename P6>
+struct Invoker<void, P1, P2, P3, P4, P5, P6> {
+ inline static void Go(
+ Arguments* args,
+ const base::Callback<void(P1, P2, P3, P4, P5, P6)>& callback,
+ const P1& a1,
+ const P2& a2,
+ const P3& a3,
+ const P4& a4,
+ const P5& a5,
+ const P6& a6) {
+ callback.Run(a1, a2, a3, a4, a5, a6);
+ }
+};
+
+template<typename R, typename P1, typename P2, typename P3, typename P4,
+ typename P5>
+struct Invoker<R, P1, P2, P3, P4, P5, void> {
+ inline static void Go(
+ Arguments* args,
+ const base::Callback<R(P1, P2, P3, P4, P5)>& callback,
+ const P1& a1,
+ const P2& a2,
+ const P3& a3,
+ const P4& a4,
+ const P5& a5) {
+ args->Return(callback.Run(a1, a2, a3, a4, a5));
+ }
+};
+template<typename P1, typename P2, typename P3, typename P4, typename P5>
+struct Invoker<void, P1, P2, P3, P4, P5, void> {
+ inline static void Go(
+ Arguments* args,
+ const base::Callback<void(P1, P2, P3, P4, P5)>& callback,
+ const P1& a1,
+ const P2& a2,
+ const P3& a3,
+ const P4& a4,
+ const P5& a5) {
+ callback.Run(a1, a2, a3, a4, a5);
+ }
+};
+
+template<typename R, typename P1, typename P2, typename P3, typename P4>
+struct Invoker<R, P1, P2, P3, P4, void, void> {
+ inline static void Go(
+ Arguments* args,
const base::Callback<R(P1, P2, P3, P4)>& callback,
const P1& a1,
const P2& a2,
@@ -99,7 +161,7 @@ struct Invoker {
}
};
template<typename P1, typename P2, typename P3, typename P4>
-struct Invoker<void, P1, P2, P3, P4> {
+struct Invoker<void, P1, P2, P3, P4, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<void(P1, P2, P3, P4)>& callback,
@@ -112,7 +174,7 @@ struct Invoker<void, P1, P2, P3, P4> {
};
template<typename R, typename P1, typename P2, typename P3>
-struct Invoker<R, P1, P2, P3, void> {
+struct Invoker<R, P1, P2, P3, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<R(P1, P2, P3)>& callback,
@@ -123,7 +185,7 @@ struct Invoker<R, P1, P2, P3, void> {
}
};
template<typename P1, typename P2, typename P3>
-struct Invoker<void, P1, P2, P3, void> {
+struct Invoker<void, P1, P2, P3, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<void(P1, P2, P3)>& callback,
@@ -135,7 +197,7 @@ struct Invoker<void, P1, P2, P3, void> {
};
template<typename R, typename P1, typename P2>
-struct Invoker<R, P1, P2, void, void> {
+struct Invoker<R, P1, P2, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<R(P1, P2)>& callback,
@@ -145,7 +207,7 @@ struct Invoker<R, P1, P2, void, void> {
}
};
template<typename P1, typename P2>
-struct Invoker<void, P1, P2, void, void> {
+struct Invoker<void, P1, P2, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<void(P1, P2)>& callback,
@@ -156,7 +218,7 @@ struct Invoker<void, P1, P2, void, void> {
};
template<typename R, typename P1>
-struct Invoker<R, P1, void, void, void> {
+struct Invoker<R, P1, void, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<R(P1)>& callback,
@@ -165,7 +227,7 @@ struct Invoker<R, P1, void, void, void> {
}
};
template<typename P1>
-struct Invoker<void, P1, void, void, void> {
+struct Invoker<void, P1, void, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<void(P1)>& callback,
@@ -175,7 +237,7 @@ struct Invoker<void, P1, void, void, void> {
};
template<typename R>
-struct Invoker<R, void, void, void, void> {
+struct Invoker<R, void, void, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<R()>& callback) {
@@ -183,7 +245,7 @@ struct Invoker<R, void, void, void, void> {
}
};
template<>
-struct Invoker<void, void, void, void, void> {
+struct Invoker<void, void, void, void, void, void, void> {
inline static void Go(
Arguments* args,
const base::Callback<void()>& callback) {
@@ -209,6 +271,18 @@ inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
*result = *args;
return true;
}
+inline bool GetNextArgument(Arguments* args, int create_flags, 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) {
+ *result = args->isolate();
+ return true;
+}
// DispatchToCallback converts all the JavaScript arguments to C++ types and
@@ -222,8 +296,10 @@ struct Dispatcher<R()> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R()> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -237,8 +313,10 @@ struct Dispatcher<R(P1)> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R(P1)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -258,8 +336,10 @@ struct Dispatcher<R(P1, P2)> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R(P1, P2)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -281,8 +361,10 @@ struct Dispatcher<R(P1, P2, P3)> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -306,8 +388,10 @@ struct Dispatcher<R(P1, P2, P3, P4)> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -328,12 +412,75 @@ struct Dispatcher<R(P1, P2, P3, P4)> {
}
};
-} // namespace internal
+template<typename R, typename P1, typename P2, typename P3, typename P4,
+ typename P5>
+struct Dispatcher<R(P1, P2, P3, P4, P5)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
+ typedef CallbackHolder<R(P1, P2, P3, P4, P5)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
-// This should be called once per-isolate to initialize the function template
-// system.
-GIN_EXPORT void InitFunctionTemplates(PerIsolateData* isolate_data);
+ typename CallbackParamTraits<P1>::LocalType a1;
+ typename CallbackParamTraits<P2>::LocalType a2;
+ typename CallbackParamTraits<P3>::LocalType a3;
+ typename CallbackParamTraits<P4>::LocalType a4;
+ typename CallbackParamTraits<P5>::LocalType a5;
+ if (!GetNextArgument(&args, holder->flags, true, &a1) ||
+ !GetNextArgument(&args, holder->flags, false, &a2) ||
+ !GetNextArgument(&args, holder->flags, false, &a3) ||
+ !GetNextArgument(&args, holder->flags, false, &a4) ||
+ !GetNextArgument(&args, holder->flags, false, &a5)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1, P2, P3, P4, P5>::Go(&args, holder->callback, a1, a2, a3, a4,
+ a5);
+ }
+};
+
+template<typename R, typename P1, typename P2, typename P3, typename P4,
+ typename P5, typename P6>
+struct Dispatcher<R(P1, P2, P3, P4, P5, P6)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
+
+ typedef CallbackHolder<R(P1, P2, P3, P4, P5, P6)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
+
+ typename CallbackParamTraits<P1>::LocalType a1;
+ typename CallbackParamTraits<P2>::LocalType a2;
+ typename CallbackParamTraits<P3>::LocalType a3;
+ typename CallbackParamTraits<P4>::LocalType a4;
+ typename CallbackParamTraits<P5>::LocalType a5;
+ typename CallbackParamTraits<P6>::LocalType a6;
+ if (!GetNextArgument(&args, holder->flags, true, &a1) ||
+ !GetNextArgument(&args, holder->flags, false, &a2) ||
+ !GetNextArgument(&args, holder->flags, false, &a3) ||
+ !GetNextArgument(&args, holder->flags, false, &a4) ||
+ !GetNextArgument(&args, holder->flags, false, &a5) ||
+ !GetNextArgument(&args, holder->flags, false, &a6)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1, P2, P3, P4, P5, P6>::Go(&args, holder->callback, a1, a2, a3,
+ a4, a5, a6);
+ }
+};
+
+} // namespace internal
// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
@@ -345,11 +492,27 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
v8::Isolate* isolate, const base::Callback<Sig> callback,
int callback_flags = 0) {
typedef internal::CallbackHolder<Sig> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(
- isolate, new HolderT(callback, callback_flags));
+ HolderT* holder = new HolderT(isolate, callback, callback_flags);
+
return v8::FunctionTemplate::New(
+ isolate,
&internal::Dispatcher<Sig>::DispatchToCallback,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
+ ConvertToV8<v8::Handle<v8::External> >(isolate,
+ holder->GetHandle(isolate)));
+}
+
+// CreateFunctionHandler installs a CallAsFunction handler on the given
+// object template that forwards to a provided C++ function or base::Callback.
+template<typename Sig>
+void CreateFunctionHandler(v8::Isolate* isolate,
+ v8::Local<v8::ObjectTemplate> tmpl,
+ const base::Callback<Sig> callback,
+ int callback_flags = 0) {
+ typedef internal::CallbackHolder<Sig> HolderT;
+ HolderT* holder = new HolderT(isolate, callback, callback_flags);
+ tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback,
+ ConvertToV8<v8::Handle<v8::External> >(
+ isolate, holder->GetHandle(isolate)));
}
} // namespace gin
diff --git a/chromium/gin/function_template.h.pump b/chromium/gin/function_template.h.pump
index fad718febc2..20b2821e0ef 100644
--- a/chromium/gin/function_template.h.pump
+++ b/chromium/gin/function_template.h.pump
@@ -8,7 +8,7 @@ $$
#ifndef GIN_FUNCTION_TEMPLATE_H_
#define GIN_FUNCTION_TEMPLATE_H_
-$var MAX_ARITY = 4
+$var MAX_ARITY = 6
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
@@ -19,11 +19,6 @@ $var MAX_ARITY = 4
#include "gin/arguments.h"
#include "gin/converter.h"
#include "gin/gin_export.h"
-#include "gin/handle.h"
-#include "gin/public/gin_embedders.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-
#include "v8/include/v8.h"
namespace gin {
@@ -51,34 +46,41 @@ struct CallbackParamTraits<const T*> {
// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from
-// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
+// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
// DispatchToCallback, where it is invoked.
-//
-// v8::FunctionTemplate only supports passing void* as data so how do we know
-// when to delete the base::Callback? That's where CallbackHolderBase comes in.
-// It inherits from Wrappable, which delete itself when both (a) the refcount
-// via base::RefCounted has dropped to zero, and (b) there are no more
-// JavaScript references in V8.
// This simple base class is used so that we can share a single object template
// among every CallbackHolder instance.
-class GIN_EXPORT CallbackHolderBase : public Wrappable<CallbackHolderBase> {
+class GIN_EXPORT CallbackHolderBase {
public:
- static WrapperInfo kWrapperInfo;
+ v8::Handle<v8::External> GetHandle(v8::Isolate* isolate);
protected:
- virtual ~CallbackHolderBase() {}
+ explicit CallbackHolderBase(v8::Isolate* isolate);
+ virtual ~CallbackHolderBase();
+
+ private:
+ static void WeakCallback(
+ const v8::WeakCallbackData<v8::External, CallbackHolderBase>& data);
+
+ v8::Persistent<v8::External> v8_ref_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase);
};
template<typename Sig>
class CallbackHolder : public CallbackHolderBase {
public:
- CallbackHolder(const base::Callback<Sig>& callback, int flags)
- : callback(callback), flags(flags) {}
+ CallbackHolder(v8::Isolate* isolate,
+ const base::Callback<Sig>& callback,
+ int flags)
+ : CallbackHolderBase(isolate), callback(callback), flags(flags) {}
base::Callback<Sig> callback;
int flags;
private:
virtual ~CallbackHolder() {}
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
};
@@ -141,6 +143,18 @@ inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
*result = *args;
return true;
}
+inline bool GetNextArgument(Arguments* args, int create_flags, 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) {
+ *result = args->isolate();
+ return true;
+}
// DispatchToCallback converts all the JavaScript arguments to C++ types and
@@ -158,8 +172,10 @@ struct Dispatcher<R($for ARG , [[P$(ARG)]])> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+ v8::Handle<v8::External> v8_holder;
+ CHECK(args.GetData(&v8_holder));
+ CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+ v8_holder->Value());
typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
@@ -187,11 +203,6 @@ $for ARG [[ typename CallbackParamTraits<P$(ARG)>::LocalType a$(ARG);
} // namespace internal
-// This should be called once per-isolate to initialize the function template
-// system.
-GIN_EXPORT void InitFunctionTemplates(PerIsolateData* isolate_data);
-
-
// 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
@@ -201,11 +212,27 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
v8::Isolate* isolate, const base::Callback<Sig> callback,
int callback_flags = 0) {
typedef internal::CallbackHolder<Sig> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(
- isolate, new HolderT(callback, callback_flags));
+ HolderT* holder = new HolderT(isolate, callback, callback_flags);
+
return v8::FunctionTemplate::New(
+ isolate,
&internal::Dispatcher<Sig>::DispatchToCallback,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
+ ConvertToV8<v8::Handle<v8::External> >(isolate,
+ holder->GetHandle(isolate)));
+}
+
+// CreateFunctionHandler installs a CallAsFunction handler on the given
+// object template that forwards to a provided C++ function or base::Callback.
+template<typename Sig>
+void CreateFunctionHandler(v8::Isolate* isolate,
+ v8::Local<v8::ObjectTemplate> tmpl,
+ const base::Callback<Sig> callback,
+ int callback_flags = 0) {
+ typedef internal::CallbackHolder<Sig> HolderT;
+ HolderT* holder = new HolderT(isolate, callback, callback_flags);
+ tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback,
+ ConvertToV8<v8::Handle<v8::External> >(
+ isolate, holder->GetHandle(isolate)));
}
} // namespace gin
diff --git a/chromium/gin/gin.gyp b/chromium/gin/gin.gyp
index 8af1e8b85e0..6ee606525f6 100644
--- a/chromium/gin/gin.gyp
+++ b/chromium/gin/gin.gyp
@@ -12,7 +12,9 @@
'type': '<(component)',
'dependencies': [
'../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../v8/tools/gyp/v8.gyp:v8',
+
],
'export_dependent_settings': [
'../base/base.gyp:base',
@@ -35,6 +37,8 @@
'function_template.h',
'gin_export.h',
'handle.h',
+ 'interceptor.cc',
+ 'interceptor.h',
'isolate_holder.cc',
'modules/console.cc',
'modules/console.h',
@@ -42,8 +46,11 @@
'modules/file_module_provider.h',
'modules/module_registry.cc',
'modules/module_registry.h',
+ 'modules/module_registry_observer.h',
'modules/module_runner_delegate.cc',
'modules/module_runner_delegate.h',
+ 'modules/timer.cc',
+ 'modules/timer.h',
'object_template_builder.cc',
'object_template_builder.h',
'per_context_data.cc',
@@ -53,11 +60,15 @@
'public/context_holder.h',
'public/gin_embedders.h',
'public/isolate_holder.h',
+ 'public/v8_platform.h',
'public/wrapper_info.h',
'runner.cc',
'runner.h',
+ 'shell_runner.cc',
+ 'shell_runner.h',
'try_catch.cc',
'try_catch.h',
+ 'v8_platform.cc',
'wrappable.cc',
'wrappable.h',
'wrapper_info.cc',
@@ -96,6 +107,8 @@
'sources': [
'test/file_runner.cc',
'test/file_runner.h',
+ 'test/gc.cc',
+ 'test/gc.h',
'test/gtest.cc',
'test/gtest.h',
'test/v8_test.cc',
@@ -106,15 +119,19 @@
'target_name': 'gin_unittests',
'type': 'executable',
'dependencies': [
- '../base/base.gyp:run_all_unittests',
+ '../base/base.gyp:test_support_base',
'../v8/tools/gyp/v8.gyp:v8',
'gin_test',
],
'sources': [
'converter_unittest.cc',
+ 'interceptor_unittest.cc',
+ 'modules/module_registry_unittest.cc',
+ 'modules/timer_unittest.cc',
+ 'per_context_data_unittest.cc',
+ 'shell_runner_unittest.cc',
'test/run_all_unittests.cc',
'test/run_js_tests.cc',
- 'runner_unittest.cc',
'wrappable_unittest.cc',
],
},
diff --git a/chromium/gin/handle.h b/chromium/gin/handle.h
index da1de347f23..01db6606f19 100644
--- a/chromium/gin/handle.h
+++ b/chromium/gin/handle.h
@@ -60,7 +60,10 @@ struct Converter<gin::Handle<T> > {
// without having to write out the type of the object explicitly.
template<typename T>
gin::Handle<T> CreateHandle(v8::Isolate* isolate, T* object) {
- return gin::Handle<T>(object->GetWrapper(isolate), object);
+ v8::Handle<v8::Object> wrapper = object->GetWrapper(isolate);
+ if (wrapper.IsEmpty())
+ return gin::Handle<T>();
+ return gin::Handle<T>(wrapper, object);
}
} // namespace gin
diff --git a/chromium/gin/interceptor.cc b/chromium/gin/interceptor.cc
new file mode 100644
index 00000000000..7efc32ee68b
--- /dev/null
+++ b/chromium/gin/interceptor.cc
@@ -0,0 +1,64 @@
+// Copyright 2014 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/interceptor.h"
+
+#include <map>
+
+#include "gin/per_isolate_data.h"
+
+namespace gin {
+
+NamedPropertyInterceptor::NamedPropertyInterceptor(v8::Isolate* isolate,
+ WrappableBase* base)
+ : isolate_(isolate), base_(base) {
+ PerIsolateData::From(isolate_)->SetNamedPropertyInterceptor(base_, this);
+}
+
+NamedPropertyInterceptor::~NamedPropertyInterceptor() {
+ PerIsolateData::From(isolate_)->ClearNamedPropertyInterceptor(base_, this);
+}
+
+v8::Local<v8::Value> NamedPropertyInterceptor::GetNamedProperty(
+ v8::Isolate* isolate,
+ const std::string& property) {
+ return v8::Local<v8::Value>();
+}
+
+void NamedPropertyInterceptor::SetNamedProperty(v8::Isolate* isolate,
+ const std::string& property,
+ v8::Local<v8::Value> value) {}
+
+std::vector<std::string> NamedPropertyInterceptor::EnumerateNamedProperties(
+ v8::Isolate* isolate) {
+ return std::vector<std::string>();
+}
+
+IndexedPropertyInterceptor::IndexedPropertyInterceptor(v8::Isolate* isolate,
+ WrappableBase* base)
+ : isolate_(isolate), base_(base) {
+ PerIsolateData::From(isolate_)->SetIndexedPropertyInterceptor(base_, this);
+}
+
+IndexedPropertyInterceptor::~IndexedPropertyInterceptor() {
+ PerIsolateData::From(isolate_)->ClearIndexedPropertyInterceptor(base_, this);
+}
+
+v8::Local<v8::Value> IndexedPropertyInterceptor::GetIndexedProperty(
+ v8::Isolate* isolate,
+ uint32_t index) {
+ return v8::Local<v8::Value>();
+}
+
+void IndexedPropertyInterceptor::SetIndexedProperty(
+ v8::Isolate* isolate,
+ uint32_t index,
+ v8::Local<v8::Value> value) {}
+
+std::vector<uint32_t> IndexedPropertyInterceptor::EnumerateIndexedProperties(
+ v8::Isolate* isolate) {
+ return std::vector<uint32_t>();
+}
+
+} // namespace gin
diff --git a/chromium/gin/interceptor.h b/chromium/gin/interceptor.h
new file mode 100644
index 00000000000..802929b8377
--- /dev/null
+++ b/chromium/gin/interceptor.h
@@ -0,0 +1,63 @@
+// Copyright 2014 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_INTERCEPTOR_H_
+#define GIN_INTERCEPTOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "gin/gin_export.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+class WrappableBase;
+
+// Base class for gin::Wrappable-derived classes that want to implement a
+// property interceptor.
+class GIN_EXPORT NamedPropertyInterceptor {
+ public:
+ NamedPropertyInterceptor(v8::Isolate* isolate, WrappableBase* base);
+ virtual ~NamedPropertyInterceptor();
+
+ virtual v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate,
+ const std::string& property);
+ virtual void SetNamedProperty(v8::Isolate* isolate,
+ const std::string& property,
+ v8::Local<v8::Value> value);
+ virtual std::vector<std::string> EnumerateNamedProperties(
+ v8::Isolate* isolate);
+
+ private:
+ v8::Isolate* isolate_;
+ WrappableBase* base_;
+
+ DISALLOW_COPY_AND_ASSIGN(NamedPropertyInterceptor);
+};
+
+class GIN_EXPORT IndexedPropertyInterceptor {
+ public:
+ IndexedPropertyInterceptor(v8::Isolate* isolate, WrappableBase* base);
+ virtual ~IndexedPropertyInterceptor();
+
+ virtual v8::Local<v8::Value> GetIndexedProperty(v8::Isolate* isolate,
+ uint32_t index);
+ virtual void SetIndexedProperty(v8::Isolate* isolate,
+ uint32_t index,
+ v8::Local<v8::Value> value);
+ virtual std::vector<uint32_t> EnumerateIndexedProperties(
+ v8::Isolate* isolate);
+
+ private:
+ v8::Isolate* isolate_;
+ WrappableBase* base_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedPropertyInterceptor);
+};
+
+} // namespace gin
+
+#endif // GIN_INTERCEPTOR_H_
diff --git a/chromium/gin/interceptor_unittest.cc b/chromium/gin/interceptor_unittest.cc
new file mode 100644
index 00000000000..ee6b7dc50a7
--- /dev/null
+++ b/chromium/gin/interceptor_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2014 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 "base/logging.h"
+#include "gin/arguments.h"
+#include "gin/handle.h"
+#include "gin/interceptor.h"
+#include "gin/object_template_builder.h"
+#include "gin/per_isolate_data.h"
+#include "gin/public/isolate_holder.h"
+#include "gin/test/v8_test.h"
+#include "gin/try_catch.h"
+#include "gin/wrappable.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gin {
+
+class MyInterceptor : public Wrappable<MyInterceptor>,
+ public NamedPropertyInterceptor,
+ public IndexedPropertyInterceptor {
+ public:
+ static WrapperInfo kWrapperInfo;
+
+ static gin::Handle<MyInterceptor> Create(v8::Isolate* isolate) {
+ return CreateHandle(isolate, new MyInterceptor(isolate));
+ }
+
+ int value() const { return value_; }
+ void set_value(int value) { value_ = value; }
+
+ // gin::NamedPropertyInterceptor
+ virtual v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate,
+ const std::string& property)
+ OVERRIDE {
+ if (property == "value") {
+ return ConvertToV8(isolate, value_);
+ } else if (property == "func") {
+ return CreateFunctionTemplate(isolate,
+ base::Bind(&MyInterceptor::Call),
+ HolderIsFirstArgument)->GetFunction();
+ } else {
+ return v8::Local<v8::Value>();
+ }
+ }
+ virtual void SetNamedProperty(v8::Isolate* isolate,
+ const std::string& property,
+ v8::Local<v8::Value> value) OVERRIDE {
+ if (property != "value")
+ return;
+ ConvertFromV8(isolate, value, &value_);
+ }
+ virtual std::vector<std::string> EnumerateNamedProperties(
+ v8::Isolate* isolate) OVERRIDE {
+ std::vector<std::string> result;
+ result.push_back("func");
+ result.push_back("value");
+ return result;
+ }
+
+ // gin::IndexedPropertyInterceptor
+ virtual v8::Local<v8::Value> GetIndexedProperty(v8::Isolate* isolate,
+ uint32_t index) OVERRIDE {
+ if (index == 0)
+ return ConvertToV8(isolate, value_);
+ return v8::Local<v8::Value>();
+ }
+ virtual void SetIndexedProperty(v8::Isolate* isolate,
+ uint32_t index,
+ v8::Local<v8::Value> value) OVERRIDE {
+ if (index != 0)
+ return;
+ ConvertFromV8(isolate, value, &value_);
+ }
+ virtual std::vector<uint32_t> EnumerateIndexedProperties(v8::Isolate* isolate)
+ OVERRIDE {
+ std::vector<uint32_t> result;
+ result.push_back(0);
+ return result;
+ }
+
+ private:
+ explicit MyInterceptor(v8::Isolate* isolate)
+ : NamedPropertyInterceptor(isolate, this),
+ IndexedPropertyInterceptor(isolate, this),
+ value_(0) {}
+ virtual ~MyInterceptor() {}
+
+ // gin::Wrappable
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate)
+ OVERRIDE {
+ return Wrappable<MyInterceptor>::GetObjectTemplateBuilder(isolate)
+ .AddNamedPropertyInterceptor()
+ .AddIndexedPropertyInterceptor();
+ }
+
+ int Call(int value) {
+ int tmp = value_;
+ value_ = value;
+ return tmp;
+ }
+
+ int value_;
+};
+
+WrapperInfo MyInterceptor::kWrapperInfo = {kEmbedderNativeGin};
+
+class InterceptorTest : public V8Test {
+ public:
+ void RunInterceptorTest(const std::string& script_source) {
+ v8::Isolate* isolate = instance_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ gin::Handle<MyInterceptor> obj = MyInterceptor::Create(isolate);
+
+ obj->set_value(42);
+ EXPECT_EQ(42, obj->value());
+
+ v8::Handle<v8::String> source = StringToV8(isolate, script_source);
+ EXPECT_FALSE(source.IsEmpty());
+
+ gin::TryCatch try_catch;
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+ EXPECT_FALSE(script.IsEmpty());
+ v8::Handle<v8::Value> val = script->Run();
+ EXPECT_FALSE(val.IsEmpty());
+ v8::Handle<v8::Function> func;
+ EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
+ v8::Handle<v8::Value> argv[] = {ConvertToV8(isolate, obj.get()), };
+ func->Call(v8::Undefined(isolate), 1, argv);
+ EXPECT_FALSE(try_catch.HasCaught());
+ EXPECT_EQ("", try_catch.GetStackTrace());
+
+ EXPECT_EQ(191, obj->value());
+ }
+};
+
+TEST_F(InterceptorTest, NamedInterceptor) {
+ RunInterceptorTest(
+ "(function (obj) {"
+ " if (obj.value !== 42) throw 'FAIL';"
+ " else obj.value = 191; })");
+}
+
+TEST_F(InterceptorTest, NamedInterceptorCall) {
+ RunInterceptorTest(
+ "(function (obj) {"
+ " if (obj.func(191) !== 42) throw 'FAIL';"
+ " })");
+}
+
+TEST_F(InterceptorTest, IndexedInterceptor) {
+ RunInterceptorTest(
+ "(function (obj) {"
+ " if (obj[0] !== 42) throw 'FAIL';"
+ " else obj[0] = 191; })");
+}
+
+} // namespace gin
diff --git a/chromium/gin/isolate_holder.cc b/chromium/gin/isolate_holder.cc
index 1929ebd0342..d0ebbb84bf2 100644
--- a/chromium/gin/isolate_holder.cc
+++ b/chromium/gin/isolate_holder.cc
@@ -13,6 +13,7 @@
#include "gin/array_buffer.h"
#include "gin/function_template.h"
#include "gin/per_isolate_data.h"
+#include "gin/public/v8_platform.h"
namespace gin {
@@ -23,8 +24,8 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
return true;
}
-
-void EnsureV8Initialized(bool gin_managed) {
+void EnsureV8Initialized(gin::IsolateHolder::ScriptMode mode,
+ bool gin_managed) {
static bool v8_is_initialized = false;
static bool v8_is_gin_managed = false;
if (v8_is_initialized) {
@@ -36,31 +37,35 @@ void EnsureV8Initialized(bool gin_managed) {
if (!gin_managed)
return;
+ v8::V8::InitializePlatform(V8Platform::Get());
v8::V8::SetArrayBufferAllocator(ArrayBufferAllocator::SharedInstance());
- static const char v8_flags[] = "--use_strict --harmony";
- v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1);
+ if (mode == gin::IsolateHolder::kStrictMode) {
+ static const char v8_flags[] = "--use_strict";
+ v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1);
+ }
v8::V8::SetEntropySource(&GenerateEntropy);
v8::V8::Initialize();
}
} // namespace
-IsolateHolder::IsolateHolder()
+IsolateHolder::IsolateHolder(ScriptMode mode)
: isolate_owner_(true) {
- EnsureV8Initialized(true);
+ EnsureV8Initialized(mode, true);
isolate_ = v8::Isolate::New();
v8::ResourceConstraints constraints;
constraints.ConfigureDefaults(base::SysInfo::AmountOfPhysicalMemory(),
+ base::SysInfo::AmountOfVirtualMemory(),
base::SysInfo::NumberOfProcessors());
v8::SetResourceConstraints(isolate_, &constraints);
- Init();
+ Init(ArrayBufferAllocator::SharedInstance());
}
-IsolateHolder::IsolateHolder(v8::Isolate* isolate)
- : isolate_owner_(false),
- isolate_(isolate) {
- EnsureV8Initialized(false);
- Init();
+IsolateHolder::IsolateHolder(v8::Isolate* isolate,
+ v8::ArrayBuffer::Allocator* allocator)
+ : isolate_owner_(false), isolate_(isolate) {
+ EnsureV8Initialized(kNonStrictMode, false);
+ Init(allocator);
}
IsolateHolder::~IsolateHolder() {
@@ -69,11 +74,10 @@ IsolateHolder::~IsolateHolder() {
isolate_->Dispose();
}
-void IsolateHolder::Init() {
+void IsolateHolder::Init(v8::ArrayBuffer::Allocator* allocator) {
v8::Isolate::Scope isolate_scope(isolate_);
v8::HandleScope handle_scope(isolate_);
- isolate_data_.reset(new PerIsolateData(isolate_));
- InitFunctionTemplates(isolate_data_.get());
+ isolate_data_.reset(new PerIsolateData(isolate_, allocator));
}
} // namespace gin
diff --git a/chromium/gin/modules/console.cc b/chromium/gin/modules/console.cc
index 14849944bfa..d172373f01d 100644
--- a/chromium/gin/modules/console.cc
+++ b/chromium/gin/modules/console.cc
@@ -9,6 +9,7 @@
#include "base/strings/string_util.h"
#include "gin/arguments.h"
#include "gin/converter.h"
+#include "gin/object_template_builder.h"
#include "gin/per_isolate_data.h"
#include "gin/public/wrapper_info.h"
@@ -18,13 +19,12 @@ namespace gin {
namespace {
-void Log(const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
-
+void Log(Arguments* args) {
std::vector<std::string> messages;
- if (!args.GetRemaining(&messages))
- return args.ThrowTypeError("Expected strings.");
-
+ if (!args->GetRemaining(&messages)) {
+ args->ThrowError();
+ return;
+ }
std::cout << JoinString(messages, ' ') << std::endl;
}
@@ -34,16 +34,16 @@ WrapperInfo g_wrapper_info = { kEmbedderNativeGin };
const char Console::kModuleName[] = "console";
-v8::Local<ObjectTemplate> Console::GetTemplate(v8::Isolate* isolate) {
+v8::Local<v8::Value> Console::GetModule(v8::Isolate* isolate) {
PerIsolateData* data = PerIsolateData::From(isolate);
v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info);
if (templ.IsEmpty()) {
- templ = ObjectTemplate::New();
- templ->Set(StringToSymbol(isolate, "log"),
- v8::FunctionTemplate::New(isolate, Log));
+ templ = ObjectTemplateBuilder(isolate)
+ .SetMethod("log", Log)
+ .Build();
data->SetObjectTemplate(&g_wrapper_info, templ);
}
- return templ;
+ return templ->NewInstance();
}
} // namespace gin
diff --git a/chromium/gin/modules/console.h b/chromium/gin/modules/console.h
index 8753961dd2b..ff8061ba4a3 100644
--- a/chromium/gin/modules/console.h
+++ b/chromium/gin/modules/console.h
@@ -15,7 +15,7 @@ namespace gin {
class GIN_EXPORT Console {
public:
static const char kModuleName[];
- static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate);
+ static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
};
} // namespace gin
diff --git a/chromium/gin/modules/file_module_provider.cc b/chromium/gin/modules/file_module_provider.cc
index 990dcd000c0..660d9b1b9ac 100644
--- a/chromium/gin/modules/file_module_provider.cc
+++ b/chromium/gin/modules/file_module_provider.cc
@@ -37,10 +37,7 @@ void AttempToLoadModule(const base::WeakPtr<Runner>& runner,
continue;
Runner::Scope scope(runner.get());
- v8::Handle<v8::Script> script = v8::Script::New(
- StringToV8(runner->isolate(), source),
- StringToV8(runner->isolate(), id));
- runner->Run(script);
+ runner->Run(source, id);
return;
}
}
diff --git a/chromium/gin/modules/module_registry.cc b/chromium/gin/modules/module_registry.cc
index 9dd3dbe9810..3712f1a41ac 100644
--- a/chromium/gin/modules/module_registry.cc
+++ b/chromium/gin/modules/module_registry.cc
@@ -10,6 +10,8 @@
#include "base/logging.h"
#include "gin/arguments.h"
#include "gin/converter.h"
+#include "gin/modules/module_registry_observer.h"
+#include "gin/per_context_data.h"
#include "gin/per_isolate_data.h"
#include "gin/public/wrapper_info.h"
#include "gin/runner.h"
@@ -47,6 +49,13 @@ PendingModule::~PendingModule() {
namespace {
+// Key for base::SupportsUserData::Data.
+const char kModuleRegistryKey[] = "ModuleRegistry";
+
+struct ModuleRegistryData : public base::SupportsUserData::Data {
+ scoped_ptr<ModuleRegistry> registry;
+};
+
void Define(const v8::FunctionCallbackInfo<Value>& info) {
Arguments args(info);
@@ -87,52 +96,67 @@ Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) {
return templ;
}
-v8::Handle<String> GetHiddenValueKey(Isolate* isolate) {
- return StringToSymbol(isolate, "::gin::ModuleRegistry");
-}
-
} // namespace
ModuleRegistry::ModuleRegistry(Isolate* isolate)
- : modules_(isolate, Object::New()) {
+ : modules_(isolate, Object::New(isolate)) {
}
ModuleRegistry::~ModuleRegistry() {
modules_.Reset();
}
+// static
void ModuleRegistry::RegisterGlobals(Isolate* isolate,
v8::Handle<ObjectTemplate> templ) {
templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate));
}
+// static
+void ModuleRegistry::InstallGlobals(v8::Isolate* isolate,
+ v8::Handle<v8::Object> obj) {
+ obj->Set(StringToSymbol(isolate, "define"),
+ GetDefineTemplate(isolate)->GetFunction());
+}
+
+// static
ModuleRegistry* ModuleRegistry::From(v8::Handle<Context> context) {
- Isolate* isolate = context->GetIsolate();
- v8::Handle<String> key = GetHiddenValueKey(isolate);
- v8::Handle<Value> value = context->Global()->GetHiddenValue(key);
- v8::Handle<External> external;
- if (value.IsEmpty() || !ConvertFromV8(isolate, value, &external)) {
- PerContextData* data = PerContextData::From(context);
- if (!data)
- return NULL;
- ModuleRegistry* registry = new ModuleRegistry(isolate);
- context->Global()->SetHiddenValue(key, External::New(isolate, registry));
- data->AddSupplement(scoped_ptr<ContextSupplement>(registry));
- return registry;
+ PerContextData* data = PerContextData::From(context);
+ if (!data)
+ return NULL;
+
+ ModuleRegistryData* registry_data = static_cast<ModuleRegistryData*>(
+ data->GetUserData(kModuleRegistryKey));
+ if (!registry_data) {
+ // PerContextData takes ownership of ModuleRegistryData.
+ registry_data = new ModuleRegistryData;
+ registry_data->registry.reset(new ModuleRegistry(context->GetIsolate()));
+ data->SetUserData(kModuleRegistryKey, registry_data);
}
- return static_cast<ModuleRegistry*>(external->Value());
+ return registry_data->registry.get();
}
-void ModuleRegistry::AddBuiltinModule(Isolate* isolate,
- const std::string& id,
- v8::Handle<ObjectTemplate> templ) {
+void ModuleRegistry::AddObserver(ModuleRegistryObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ModuleRegistry::RemoveObserver(ModuleRegistryObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id,
+ v8::Handle<Value> module) {
DCHECK(!id.empty());
- RegisterModule(isolate, id, templ->NewInstance());
+ RegisterModule(isolate, id, module);
}
void ModuleRegistry::AddPendingModule(Isolate* isolate,
scoped_ptr<PendingModule> pending) {
+ const std::string pending_id = pending->id;
+ const std::vector<std::string> pending_dependencies = pending->dependencies;
AttemptToLoad(isolate, pending.Pass());
+ FOR_EACH_OBSERVER(ModuleRegistryObserver, observer_list_,
+ OnDidAddPendingModule(pending_id, pending_dependencies));
}
void ModuleRegistry::LoadModule(Isolate* isolate,
@@ -169,11 +193,6 @@ void ModuleRegistry::RegisterModule(Isolate* isolate,
callback.Run(module);
}
-void ModuleRegistry::Detach(v8::Handle<Context> context) {
- context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()),
- v8::Handle<Value>());
-}
-
bool ModuleRegistry::CheckDependencies(PendingModule* pending) {
size_t num_missing_dependencies = 0;
size_t len = pending->dependencies.size();
diff --git a/chromium/gin/modules/module_registry.h b/chromium/gin/modules/module_registry.h
index 27606cd9a54..5775a34a3db 100644
--- a/chromium/gin/modules/module_registry.h
+++ b/chromium/gin/modules/module_registry.h
@@ -13,11 +13,14 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
#include "gin/gin_export.h"
-#include "gin/per_context_data.h"
+#include "v8/include/v8.h"
namespace gin {
+class ModuleRegistryObserver;
struct PendingModule;
// This class implements the Asynchronous Module Definition (AMD) API.
@@ -31,7 +34,7 @@ struct PendingModule;
// function. The spec says we should only add that property once our
// implementation complies with the specification.
//
-class GIN_EXPORT ModuleRegistry : public ContextSupplement {
+class GIN_EXPORT ModuleRegistry {
public:
typedef base::Callback<void (v8::Handle<v8::Value>)> LoadModuleCallback;
@@ -42,10 +45,16 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement {
static void RegisterGlobals(v8::Isolate* isolate,
v8::Handle<v8::ObjectTemplate> templ);
+ // Installs the necessary functions needed for modules.
+ // WARNING: this may execute script in the page.
+ static void InstallGlobals(v8::Isolate* isolate, v8::Handle<v8::Object> obj);
+
+ void AddObserver(ModuleRegistryObserver* observer);
+ void RemoveObserver(ModuleRegistryObserver* observer);
+
// The caller must have already entered our context.
- void AddBuiltinModule(v8::Isolate* isolate,
- const std::string& id,
- v8::Handle<v8::ObjectTemplate> templ);
+ void AddBuiltinModule(v8::Isolate* isolate, const std::string& id,
+ v8::Handle<v8::Value> module);
// The caller must have already entered our context.
void AddPendingModule(v8::Isolate* isolate,
@@ -72,9 +81,6 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement {
explicit ModuleRegistry(v8::Isolate* isolate);
- // From ContextSupplement:
- virtual void Detach(v8::Handle<v8::Context> context) OVERRIDE;
-
void Load(v8::Isolate* isolate, scoped_ptr<PendingModule> pending);
void RegisterModule(v8::Isolate* isolate,
const std::string& id,
@@ -93,6 +99,8 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement {
PendingModuleVector pending_modules_;
v8::Persistent<v8::Object> modules_;
+ ObserverList<ModuleRegistryObserver> observer_list_;
+
DISALLOW_COPY_AND_ASSIGN(ModuleRegistry);
};
diff --git a/chromium/gin/modules/module_registry_observer.h b/chromium/gin/modules/module_registry_observer.h
new file mode 100644
index 00000000000..68ee4adc759
--- /dev/null
+++ b/chromium/gin/modules/module_registry_observer.h
@@ -0,0 +1,31 @@
+// Copyright 2014 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_MODULES_MODULE_REGISTRY_OBSERVER_H_
+#define GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_
+
+#include <string>
+#include <vector>
+
+#include "gin/gin_export.h"
+
+namespace gin {
+
+// Notified of interesting events from ModuleRegistry.
+class GIN_EXPORT ModuleRegistryObserver {
+ public:
+ // Called from AddPendingModule(). |id| is the id/name of the module and
+ // |dependencies| this list of modules |id| depends upon.
+ virtual void OnDidAddPendingModule(
+ const std::string& id,
+ const std::vector<std::string>& dependencies) = 0;
+
+ protected:
+ virtual ~ModuleRegistryObserver() {}
+};
+
+} // namespace gin
+
+#endif // GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_
+
diff --git a/chromium/gin/modules/module_registry_unittest.cc b/chromium/gin/modules/module_registry_unittest.cc
new file mode 100644
index 00000000000..0ffdc0c3dd5
--- /dev/null
+++ b/chromium/gin/modules/module_registry_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 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/modules/module_registry.h"
+
+#include "base/message_loop/message_loop.h"
+#include "gin/modules/module_registry_observer.h"
+#include "gin/modules/module_runner_delegate.h"
+#include "gin/public/context_holder.h"
+#include "gin/public/isolate_holder.h"
+#include "gin/shell_runner.h"
+#include "gin/test/v8_test.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+namespace {
+
+struct TestHelper {
+ TestHelper(v8::Isolate* isolate)
+ : delegate(std::vector<base::FilePath>()),
+ runner(new ShellRunner(&delegate, isolate)),
+ scope(runner.get()) {
+ }
+
+ base::MessageLoop message_loop;
+ ModuleRunnerDelegate delegate;
+ scoped_ptr<ShellRunner> runner;
+ Runner::Scope scope;
+};
+
+class ModuleRegistryObserverImpl : public ModuleRegistryObserver {
+ public:
+ ModuleRegistryObserverImpl() : did_add_count_(0) {}
+
+ virtual void OnDidAddPendingModule(
+ const std::string& id,
+ const std::vector<std::string>& dependencies) OVERRIDE {
+ did_add_count_++;
+ id_ = id;
+ dependencies_ = dependencies;
+ }
+
+ int did_add_count() { return did_add_count_; }
+ const std::string& id() const { return id_; }
+ const std::vector<std::string>& dependencies() const { return dependencies_; }
+
+ private:
+ int did_add_count_;
+ std::string id_;
+ std::vector<std::string> dependencies_;
+
+ DISALLOW_COPY_AND_ASSIGN(ModuleRegistryObserverImpl);
+};
+
+} // namespace
+
+typedef V8Test ModuleRegistryTest;
+
+// Verifies ModuleRegistry is not available after ContextHolder has been
+// deleted.
+TEST_F(ModuleRegistryTest, DestroyedWithContext) {
+ v8::Isolate::Scope isolate_scope(instance_->isolate());
+ v8::HandleScope handle_scope(instance_->isolate());
+ v8::Handle<v8::Context> context = v8::Context::New(
+ instance_->isolate(), NULL, v8::Handle<v8::ObjectTemplate>());
+ {
+ ContextHolder context_holder(instance_->isolate());
+ context_holder.SetContext(context);
+ ModuleRegistry* registry = ModuleRegistry::From(context);
+ EXPECT_TRUE(registry != NULL);
+ }
+ ModuleRegistry* registry = ModuleRegistry::From(context);
+ EXPECT_TRUE(registry == NULL);
+}
+
+// Verifies ModuleRegistryObserver is notified appropriately.
+TEST_F(ModuleRegistryTest, ModuleRegistryObserverTest) {
+ TestHelper helper(instance_->isolate());
+ std::string source =
+ "define('id', ['dep1', 'dep2'], function() {"
+ " return function() {};"
+ "});";
+
+ ModuleRegistryObserverImpl observer;
+ ModuleRegistry::From(helper.runner->GetContextHolder()->context())->
+ AddObserver(&observer);
+ helper.runner->Run(source, "script");
+ ModuleRegistry::From(helper.runner->GetContextHolder()->context())->
+ RemoveObserver(&observer);
+ EXPECT_EQ(1, observer.did_add_count());
+ EXPECT_EQ("id", observer.id());
+ ASSERT_EQ(2u, observer.dependencies().size());
+ EXPECT_EQ("dep1", observer.dependencies()[0]);
+ EXPECT_EQ("dep2", observer.dependencies()[1]);
+}
+
+} // namespace gin
diff --git a/chromium/gin/modules/module_runner_delegate.cc b/chromium/gin/modules/module_runner_delegate.cc
index 9bf2863c203..16b5afd0303 100644
--- a/chromium/gin/modules/module_runner_delegate.cc
+++ b/chromium/gin/modules/module_runner_delegate.cc
@@ -5,6 +5,8 @@
#include "gin/modules/module_runner_delegate.h"
#include "gin/modules/module_registry.h"
+#include "gin/object_template_builder.h"
+#include "gin/public/context_holder.h"
namespace gin {
@@ -17,38 +19,40 @@ ModuleRunnerDelegate::~ModuleRunnerDelegate() {
}
void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id,
- ModuleTemplateGetter templ) {
- builtin_modules_[id] = templ;
+ ModuleGetter getter) {
+ builtin_modules_[id] = getter;
}
void ModuleRunnerDelegate::AttemptToLoadMoreModules(Runner* runner) {
- ModuleRegistry* registry = ModuleRegistry::From(runner->context());
- registry->AttemptToLoadMoreModules(runner->isolate());
+ ModuleRegistry* registry = ModuleRegistry::From(
+ runner->GetContextHolder()->context());
+ registry->AttemptToLoadMoreModules(runner->GetContextHolder()->isolate());
module_provider_.AttempToLoadModules(
runner, registry->unsatisfied_dependencies());
}
v8::Handle<v8::ObjectTemplate> ModuleRunnerDelegate::GetGlobalTemplate(
- Runner* runner) {
- v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
- ModuleRegistry::RegisterGlobals(runner->isolate(), templ);
+ ShellRunner* runner,
+ v8::Isolate* isolate) {
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate).Build();
+ ModuleRegistry::RegisterGlobals(isolate, templ);
return templ;
}
-void ModuleRunnerDelegate::DidCreateContext(Runner* runner) {
- RunnerDelegate::DidCreateContext(runner);
+void ModuleRunnerDelegate::DidCreateContext(ShellRunner* runner) {
+ ShellRunnerDelegate::DidCreateContext(runner);
- v8::Handle<v8::Context> context = runner->context();
+ v8::Handle<v8::Context> context = runner->GetContextHolder()->context();
ModuleRegistry* registry = ModuleRegistry::From(context);
+ v8::Isolate* isolate = runner->GetContextHolder()->isolate();
for (BuiltinModuleMap::const_iterator it = builtin_modules_.begin();
it != builtin_modules_.end(); ++it) {
- registry->AddBuiltinModule(runner->isolate(), it->first,
- it->second(runner->isolate()));
+ registry->AddBuiltinModule(isolate, it->first, it->second(isolate));
}
}
-void ModuleRunnerDelegate::DidRunScript(Runner* runner) {
+void ModuleRunnerDelegate::DidRunScript(ShellRunner* runner) {
AttemptToLoadMoreModules(runner);
}
diff --git a/chromium/gin/modules/module_runner_delegate.h b/chromium/gin/modules/module_runner_delegate.h
index 06077f479bb..09d4582dd76 100644
--- a/chromium/gin/modules/module_runner_delegate.h
+++ b/chromium/gin/modules/module_runner_delegate.h
@@ -10,40 +10,35 @@
#include "base/compiler_specific.h"
#include "gin/gin_export.h"
#include "gin/modules/file_module_provider.h"
-#include "gin/runner.h"
+#include "gin/shell_runner.h"
namespace gin {
-typedef v8::Local<v8::ObjectTemplate> (*ModuleTemplateGetter)(
- v8::Isolate* isolate);
+typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate);
// Emebedders that use AMD modules will probably want to use a RunnerDelegate
// that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders
// register built-in modules and routes module requests to FileModuleProvider.
-class GIN_EXPORT ModuleRunnerDelegate : public RunnerDelegate {
+class GIN_EXPORT ModuleRunnerDelegate : public ShellRunnerDelegate {
public:
explicit ModuleRunnerDelegate(
const std::vector<base::FilePath>& search_paths);
virtual ~ModuleRunnerDelegate();
- // Lets you register a built-in module. Built-in modules are instantiated by
- // creating a new instance of a v8::ObjectTemplate rather than by executing
- // code. This function takes a ModuleTemplateGetter rather than a
- // v8::ObjectTemplate directly so that embedders can create object templates
- // lazily.
- void AddBuiltinModule(const std::string& id, ModuleTemplateGetter templ);
+ void AddBuiltinModule(const std::string& id, ModuleGetter getter);
protected:
void AttemptToLoadMoreModules(Runner* runner);
private:
- typedef std::map<std::string, ModuleTemplateGetter> BuiltinModuleMap;
+ typedef std::map<std::string, ModuleGetter> BuiltinModuleMap;
- // From RunnerDelegate:
+ // From ShellRunnerDelegate:
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
- Runner* runner) OVERRIDE;
- virtual void DidCreateContext(Runner* runner) OVERRIDE;
- virtual void DidRunScript(Runner* runner) OVERRIDE;
+ ShellRunner* runner,
+ v8::Isolate* isolate) OVERRIDE;
+ virtual void DidCreateContext(ShellRunner* runner) OVERRIDE;
+ virtual void DidRunScript(ShellRunner* runner) OVERRIDE;
BuiltinModuleMap builtin_modules_;
FileModuleProvider module_provider_;
diff --git a/chromium/gin/modules/timer.cc b/chromium/gin/modules/timer.cc
new file mode 100644
index 00000000000..3196dda4258
--- /dev/null
+++ b/chromium/gin/modules/timer.cc
@@ -0,0 +1,103 @@
+// Copyright 2013 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/modules/timer.h"
+
+#include "base/bind.h"
+#include "gin/object_template_builder.h"
+#include "gin/per_context_data.h"
+
+namespace gin {
+
+namespace {
+
+v8::Handle<v8::String> GetHiddenPropertyName(v8::Isolate* isolate) {
+ return gin::StringToSymbol(isolate, "::gin::Timer");
+}
+
+} // namespace
+
+// Timer =======================================================================
+
+gin::WrapperInfo Timer::kWrapperInfo = { gin::kEmbedderNativeGin };
+
+// static
+Handle<Timer> Timer::Create(TimerType type, v8::Isolate* isolate, int delay_ms,
+ v8::Handle<v8::Function> function) {
+ return CreateHandle(isolate, new Timer(isolate, type == TYPE_REPEATING,
+ delay_ms, function));
+}
+
+ObjectTemplateBuilder Timer::GetObjectTemplateBuilder(v8::Isolate* isolate) {
+ // We use Unretained() here because we directly own timer_, so we know it will
+ // be alive when these methods are called.
+ return Wrappable<Timer>::GetObjectTemplateBuilder(isolate)
+ .SetMethod("cancel",
+ base::Bind(&base::Timer::Stop, base::Unretained(&timer_)))
+ .SetMethod("reset",
+ base::Bind(&base::Timer::Reset, base::Unretained(&timer_)));
+}
+
+Timer::Timer(v8::Isolate* isolate, bool repeating, int delay_ms,
+ v8::Handle<v8::Function> function)
+ : weak_factory_(this),
+ timer_(false, repeating),
+ runner_(PerContextData::From(
+ isolate->GetCurrentContext())->runner()->GetWeakPtr()) {
+ GetWrapper(runner_->GetContextHolder()->isolate())->SetHiddenValue(
+ GetHiddenPropertyName(isolate), function);
+ timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms),
+ base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr()));
+}
+
+Timer::~Timer() {
+}
+
+void Timer::OnTimerFired() {
+ // This can happen in spite of the weak callback because it is possible for
+ // a gin::Handle<> to keep this object alive past when the isolate it is part
+ // of is destroyed.
+ if (!runner_.get()) {
+ return;
+ }
+
+ Runner::Scope scope(runner_.get());
+ v8::Isolate* isolate = runner_->GetContextHolder()->isolate();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(
+ GetWrapper(isolate)->GetHiddenValue(GetHiddenPropertyName(isolate)));
+ runner_->Call(function, v8::Undefined(isolate), 0, NULL);
+}
+
+
+// TimerModule =================================================================
+
+const char TimerModule::kName[] = "timer";
+WrapperInfo TimerModule::kWrapperInfo = { kEmbedderNativeGin };
+
+// static
+Handle<TimerModule> TimerModule::Create(v8::Isolate* isolate) {
+ return CreateHandle(isolate, new TimerModule());
+}
+
+// static
+v8::Local<v8::Value> TimerModule::GetModule(v8::Isolate* isolate) {
+ return Create(isolate)->GetWrapper(isolate);
+}
+
+TimerModule::TimerModule() {
+}
+
+TimerModule::~TimerModule() {
+}
+
+ObjectTemplateBuilder TimerModule::GetObjectTemplateBuilder(
+ v8::Isolate* isolate) {
+ return Wrappable<TimerModule>::GetObjectTemplateBuilder(isolate)
+ .SetMethod("createOneShot",
+ base::Bind(&Timer::Create, Timer::TYPE_ONE_SHOT))
+ .SetMethod("createRepeating",
+ base::Bind(&Timer::Create, Timer::TYPE_REPEATING));
+}
+
+} // namespace gin
diff --git a/chromium/gin/modules/timer.h b/chromium/gin/modules/timer.h
new file mode 100644
index 00000000000..e2bed2e56fb
--- /dev/null
+++ b/chromium/gin/modules/timer.h
@@ -0,0 +1,64 @@
+// Copyright 2013 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_MODULES_TIMER_H_
+#define GIN_MODULES_TIMER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "gin/gin_export.h"
+#include "gin/handle.h"
+#include "gin/runner.h"
+#include "gin/wrappable.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+class ObjectTemplateBuilder;
+
+// A simple scriptable timer that can work in one-shot or repeating mode.
+class GIN_EXPORT Timer : public Wrappable<Timer> {
+ public:
+ enum TimerType {
+ TYPE_ONE_SHOT,
+ TYPE_REPEATING
+ };
+
+ static WrapperInfo kWrapperInfo;
+ static Handle<Timer> Create(TimerType type, v8::Isolate* isolate,
+ int delay_ms, v8::Handle<v8::Function> function);
+
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE;
+
+ private:
+ Timer(v8::Isolate* isolate, bool repeating, int delay_ms,
+ v8::Handle<v8::Function> function);
+ virtual ~Timer();
+ void OnTimerFired();
+
+ base::WeakPtrFactory<Timer> weak_factory_;
+ base::Timer timer_;
+ base::WeakPtr<gin::Runner> runner_;
+};
+
+
+class GIN_EXPORT TimerModule : public Wrappable<TimerModule> {
+ public:
+ static const char kName[];
+ static WrapperInfo kWrapperInfo;
+ static Handle<TimerModule> Create(v8::Isolate* isolate);
+ static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
+
+ private:
+ TimerModule();
+ virtual ~TimerModule();
+
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE;
+};
+
+} // namespace gin
+
+#endif // GIN_MODULES_TIMER_H_
diff --git a/chromium/gin/modules/timer_unittest.cc b/chromium/gin/modules/timer_unittest.cc
new file mode 100644
index 00000000000..f7fd8f22e67
--- /dev/null
+++ b/chromium/gin/modules/timer_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2013 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/modules/timer.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+#include "gin/public/isolate_holder.h"
+#include "gin/shell_runner.h"
+#include "gin/test/v8_test.h"
+#include "gin/try_catch.h"
+#include "gin/wrappable.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+namespace {
+
+class Result : public Wrappable<Result> {
+ public:
+ static WrapperInfo kWrapperInfo;
+ static Handle<Result> Create(v8::Isolate* isolate) {
+ return CreateHandle(isolate, new Result());
+ }
+
+ int count() const { return count_; }
+ void set_count(int count) { count_ = count; }
+
+ void Quit() {
+ base::MessageLoop::current()->QuitNow();
+ }
+
+ private:
+ Result() : count_(0) {
+ }
+
+ virtual ~Result() {
+ }
+
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE {
+ return Wrappable<Result>::GetObjectTemplateBuilder(isolate)
+ .SetProperty("count", &Result::count, &Result::set_count)
+ .SetMethod("quit", &Result::Quit);
+ }
+
+ int count_;
+};
+
+WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin };
+
+struct TestHelper {
+ TestHelper(v8::Isolate* isolate)
+ : runner(new ShellRunner(&delegate, isolate)),
+ scope(runner.get()),
+ timer_module(TimerModule::Create(isolate)),
+ result(Result::Create(isolate)) {
+ EXPECT_FALSE(runner->global().IsEmpty());
+ runner->global()->Set(StringToV8(isolate, "timer"),
+ timer_module->GetWrapper(isolate));
+ runner->global()->Set(StringToV8(isolate, "result"),
+ result->GetWrapper(isolate));
+ }
+
+ void QuitSoon() {
+ loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ base::TimeDelta::FromMilliseconds(0));
+ }
+
+ ShellRunnerDelegate delegate;
+ scoped_ptr<ShellRunner> runner;
+ Runner::Scope scope;
+ Handle<TimerModule> timer_module;
+ Handle<Result> result;
+ base::MessageLoop loop;
+};
+
+} // namespace
+
+typedef V8Test TimerUnittest;
+
+TEST_F(TimerUnittest, OneShot) {
+ TestHelper helper(instance_->isolate());
+ std::string source =
+ "timer.createOneShot(0, function() {"
+ " result.count++;"
+ "});";
+
+ helper.runner->Run(source, "script");
+ EXPECT_EQ(0, helper.result->count());
+
+ helper.QuitSoon();
+ helper.loop.Run();
+ EXPECT_EQ(1, helper.result->count());
+}
+
+TEST_F(TimerUnittest, OneShotCancel) {
+ TestHelper helper(instance_->isolate());
+ std::string source =
+ "var t = timer.createOneShot(0, function() {"
+ " result.count++;"
+ "});"
+ "t.cancel()";
+
+ helper.runner->Run(source, "script");
+ EXPECT_EQ(0, helper.result->count());
+
+ helper.QuitSoon();
+ helper.loop.Run();
+ EXPECT_EQ(0, helper.result->count());
+}
+
+TEST_F(TimerUnittest, Repeating) {
+ TestHelper helper(instance_->isolate());
+
+ // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create
+ // test case and report.
+ std::string source =
+ "timer.createRepeating(0, function() {"
+ " result.count++;"
+ " if (result.count == 3) {"
+ " result.quit();"
+ " }"
+ "});";
+
+ helper.runner->Run(source, "script");
+ EXPECT_EQ(0, helper.result->count());
+
+ helper.loop.Run();
+ EXPECT_EQ(3, helper.result->count());
+}
+
+TEST_F(TimerUnittest, TimerCallbackToDestroyedRunner) {
+ TestHelper helper(instance_->isolate());
+ std::string source =
+ "timer.createOneShot(0, function() {"
+ " result.count++;"
+ "});";
+
+ helper.runner->Run(source, "script");
+ EXPECT_EQ(0, helper.result->count());
+
+ // Destroy runner, which should destroy the timer object we created.
+ helper.QuitSoon();
+ helper.runner.reset(NULL);
+ helper.loop.Run();
+
+ // Timer should not have run because it was deleted.
+ EXPECT_EQ(0, helper.result->count());
+}
+
+} // namespace gin
diff --git a/chromium/gin/object_template_builder.cc b/chromium/gin/object_template_builder.cc
index 6dc6d2fe849..603166cfabf 100644
--- a/chromium/gin/object_template_builder.cc
+++ b/chromium/gin/object_template_builder.cc
@@ -4,15 +4,158 @@
#include "gin/object_template_builder.h"
+#include "gin/interceptor.h"
+#include "gin/per_isolate_data.h"
+#include "gin/public/wrapper_info.h"
+
namespace gin {
+namespace {
+
+WrappableBase* WrappableFromV8(v8::Isolate* isolate,
+ v8::Handle<v8::Value> val) {
+ if (!val->IsObject())
+ return NULL;
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
+ WrapperInfo* info = WrapperInfo::From(obj);
+
+ // If this fails, the object is not managed by Gin.
+ if (!info)
+ return NULL;
+
+ // We don't further validate the type of the object, but assume it's derived
+ // from WrappableBase. We look up the pointer in a global registry, to make
+ // sure it's actually pointed to a valid life object.
+ return static_cast<WrappableBase*>(
+ obj->GetAlignedPointerFromInternalField(kEncodedValueIndex));
+}
+
+NamedPropertyInterceptor* NamedInterceptorFromV8(v8::Isolate* isolate,
+ v8::Handle<v8::Value> val) {
+ WrappableBase* base = WrappableFromV8(isolate, val);
+ if (!base)
+ return NULL;
+ return PerIsolateData::From(isolate)->GetNamedPropertyInterceptor(base);
+}
+
+IndexedPropertyInterceptor* IndexedInterceptorFromV8(
+ v8::Isolate* isolate,
+ v8::Handle<v8::Value> val) {
+ WrappableBase* base = WrappableFromV8(isolate, val);
+ if (!base)
+ return NULL;
+ return PerIsolateData::From(isolate)->GetIndexedPropertyInterceptor(base);
+}
+
+void NamedPropertyGetter(v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ NamedPropertyInterceptor* interceptor =
+ NamedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ std::string name;
+ ConvertFromV8(isolate, property, &name);
+ info.GetReturnValue().Set(interceptor->GetNamedProperty(isolate, name));
+}
+
+void NamedPropertySetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ NamedPropertyInterceptor* interceptor =
+ NamedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ std::string name;
+ ConvertFromV8(isolate, property, &name);
+ interceptor->SetNamedProperty(isolate, name, value);
+}
+
+void NamedPropertyQuery(v8::Local<v8::String> property,
+ const v8::PropertyCallbackInfo<v8::Integer>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ NamedPropertyInterceptor* interceptor =
+ NamedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ std::string name;
+ ConvertFromV8(isolate, property, &name);
+ if (interceptor->GetNamedProperty(isolate, name).IsEmpty())
+ return;
+ info.GetReturnValue().Set(0);
+}
+
+void NamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ NamedPropertyInterceptor* interceptor =
+ NamedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ info.GetReturnValue().Set(v8::Handle<v8::Array>::Cast(
+ ConvertToV8(isolate, interceptor->EnumerateNamedProperties(isolate))));
+}
+
+void IndexedPropertyGetter(uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ IndexedPropertyInterceptor* interceptor =
+ IndexedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ info.GetReturnValue().Set(interceptor->GetIndexedProperty(isolate, index));
+}
+
+void IndexedPropertySetter(uint32_t index,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ IndexedPropertyInterceptor* interceptor =
+ IndexedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ interceptor->SetIndexedProperty(isolate, index, value);
+}
+
+void IndexedPropertyEnumerator(
+ const v8::PropertyCallbackInfo<v8::Array>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ IndexedPropertyInterceptor* interceptor =
+ IndexedInterceptorFromV8(isolate, info.Holder());
+ if (!interceptor)
+ return;
+ info.GetReturnValue().Set(v8::Handle<v8::Array>::Cast(
+ ConvertToV8(isolate, interceptor->EnumerateIndexedProperties(isolate))));
+}
+
+} // namespace
+
ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate)
: isolate_(isolate), template_(v8::ObjectTemplate::New(isolate)) {
+ template_->SetInternalFieldCount(kNumberOfInternalFields);
}
ObjectTemplateBuilder::~ObjectTemplateBuilder() {
}
+ObjectTemplateBuilder& ObjectTemplateBuilder::AddNamedPropertyInterceptor() {
+ template_->SetNamedPropertyHandler(&NamedPropertyGetter,
+ &NamedPropertySetter,
+ &NamedPropertyQuery,
+ NULL,
+ &NamedPropertyEnumerator);
+ return *this;
+}
+
+ObjectTemplateBuilder& ObjectTemplateBuilder::AddIndexedPropertyInterceptor() {
+ template_->SetIndexedPropertyHandler(&IndexedPropertyGetter,
+ &IndexedPropertySetter,
+ NULL,
+ NULL,
+ &IndexedPropertyEnumerator);
+ return *this;
+}
+
ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(
const base::StringPiece& name, v8::Handle<v8::Data> val) {
template_->Set(StringToSymbol(isolate_, name), val);
diff --git a/chromium/gin/object_template_builder.h b/chromium/gin/object_template_builder.h
index 6367b71245c..3d025a9deb1 100644
--- a/chromium/gin/object_template_builder.h
+++ b/chromium/gin/object_template_builder.h
@@ -27,6 +27,11 @@ struct CallbackTraits {
T callback) {
return CreateFunctionTemplate(isolate, base::Bind(callback));
}
+ static void SetAsFunctionHandler(v8::Isolate* isolate,
+ v8::Local<v8::ObjectTemplate> tmpl,
+ T callback) {
+ CreateFunctionHandler(isolate, tmpl, base::Bind(callback));
+ }
};
// Specialization for base::Callback.
@@ -36,6 +41,11 @@ struct CallbackTraits<base::Callback<T> > {
v8::Isolate* isolate, const base::Callback<T>& callback) {
return CreateFunctionTemplate(isolate, callback);
}
+ static void SetAsFunctionHandler(v8::Isolate* isolate,
+ v8::Local<v8::ObjectTemplate> tmpl,
+ const base::Callback<T>& callback) {
+ CreateFunctionHandler(isolate, tmpl, callback);
+ }
};
// Specialization for member function pointers. We need to handle this case
@@ -50,6 +60,12 @@ struct CallbackTraits<T, typename base::enable_if<
return CreateFunctionTemplate(isolate, base::Bind(callback),
HolderIsFirstArgument);
}
+ static void SetAsFunctionHandler(v8::Isolate* isolate,
+ v8::Local<v8::ObjectTemplate> tmpl,
+ T callback) {
+ CreateFunctionHandler(
+ isolate, tmpl, base::Bind(callback), HolderIsFirstArgument);
+ }
};
// This specialization allows people to construct function templates directly if
@@ -103,6 +119,13 @@ class GIN_EXPORT ObjectTemplateBuilder {
CallbackTraits<T>::CreateTemplate(isolate_, getter),
CallbackTraits<U>::CreateTemplate(isolate_, setter));
}
+ template<typename T>
+ ObjectTemplateBuilder& SetCallAsFunctionHandler(const T& callback) {
+ CallbackTraits<T>::SetAsFunctionHandler(isolate_, template_, callback);
+ return *this;
+ }
+ ObjectTemplateBuilder& AddNamedPropertyInterceptor();
+ ObjectTemplateBuilder& AddIndexedPropertyInterceptor();
v8::Local<v8::ObjectTemplate> Build();
diff --git a/chromium/gin/per_context_data.cc b/chromium/gin/per_context_data.cc
index 5183d00102b..178c0d122c1 100644
--- a/chromium/gin/per_context_data.cc
+++ b/chromium/gin/per_context_data.cc
@@ -10,43 +10,24 @@
namespace gin {
-ContextSupplement::ContextSupplement() {
-}
-
-ContextSupplement::~ContextSupplement() {
-}
-
-PerContextData::PerContextData(v8::Handle<v8::Context> context)
- : runner_(NULL) {
+PerContextData::PerContextData(ContextHolder* context_holder,
+ v8::Handle<v8::Context> context)
+ : context_holder_(context_holder),
+ runner_(NULL) {
context->SetAlignedPointerInEmbedderData(
kPerContextDataStartIndex + kEmbedderNativeGin, this);
}
PerContextData::~PerContextData() {
- DCHECK(supplements_.empty());
-}
-
-void PerContextData::Detach(v8::Handle<v8::Context> context) {
- DCHECK(From(context) == this);
- context->SetAlignedPointerInEmbedderData(
+ v8::HandleScope handle_scope(context_holder_->isolate());
+ context_holder_->context()->SetAlignedPointerInEmbedderData(
kPerContextDataStartIndex + kEmbedderNativeGin, NULL);
-
- SuplementVector supplements;
- supplements.swap(supplements_);
-
- for (SuplementVector::iterator it = supplements.begin();
- it != supplements.end(); ++it) {
- (*it)->Detach(context);
- }
}
+// static
PerContextData* PerContextData::From(v8::Handle<v8::Context> context) {
return static_cast<PerContextData*>(
context->GetAlignedPointerFromEmbedderData(kEncodedValueIndex));
}
-void PerContextData::AddSupplement(scoped_ptr<ContextSupplement> supplement) {
- supplements_.push_back(supplement.release());
-}
-
} // namespace gin
diff --git a/chromium/gin/per_context_data.h b/chromium/gin/per_context_data.h
index 3ad68d2d37c..0d1165345df 100644
--- a/chromium/gin/per_context_data.h
+++ b/chromium/gin/per_context_data.h
@@ -6,53 +6,39 @@
#define GIN_PER_CONTEXT_DATA_H_
#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
+#include "base/supports_user_data.h"
#include "gin/gin_export.h"
#include "v8/include/v8.h"
namespace gin {
+class ContextHolder;
class Runner;
-// Embedders can store additional per-context data by subclassing
-// ContextSupplement.
-class GIN_EXPORT ContextSupplement {
- public:
- ContextSupplement();
- virtual ~ContextSupplement();
-
- // Detach will be called before ContextHolder disposes the v8::Context.
- // Embedders should not interact with |context| after Detach has been called.
- virtual void Detach(v8::Handle<v8::Context> context) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContextSupplement);
-};
-
// There is one instance of PerContextData per v8::Context managed by Gin. This
-// class stores all the Gin-related data that varies per context.
-class GIN_EXPORT PerContextData {
+// class stores all the Gin-related data that varies per context. Arbitrary data
+// can be associated with this class by way of the SupportsUserData methods.
+// Instances of this class (and any associated user data) are destroyed before
+// the associated v8::Context.
+class GIN_EXPORT PerContextData : public base::SupportsUserData {
public:
- explicit PerContextData(v8::Handle<v8::Context> context);
- ~PerContextData();
+ PerContextData(ContextHolder* context_holder,
+ v8::Handle<v8::Context> context);
+ virtual ~PerContextData();
// Can return NULL after the ContextHolder has detached from context.
- static PerContextData* From(v8::Handle<v8::Context>);
- void Detach(v8::Handle<v8::Context> context);
+ static PerContextData* From(v8::Handle<v8::Context> context);
// The Runner associated with this context. To execute script in this context,
// please use the appropriate API on Runner.
Runner* runner() const { return runner_; }
void set_runner(Runner* runner) { runner_ = runner; }
- void AddSupplement(scoped_ptr<ContextSupplement> supplement);
+ ContextHolder* context_holder() { return context_holder_; }
private:
- typedef ScopedVector<ContextSupplement> SuplementVector;
-
+ ContextHolder* context_holder_;
Runner* runner_;
- SuplementVector supplements_;
DISALLOW_COPY_AND_ASSIGN(PerContextData);
};
diff --git a/chromium/gin/per_context_data_unittest.cc b/chromium/gin/per_context_data_unittest.cc
new file mode 100644
index 00000000000..4d795871950
--- /dev/null
+++ b/chromium/gin/per_context_data_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 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/per_context_data.h"
+
+#include "gin/public/context_holder.h"
+#include "gin/public/isolate_holder.h"
+#include "gin/test/v8_test.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+typedef V8Test PerContextDataTest;
+
+// Verifies PerContextData can be looked up by context and that it is not
+// available once ContextHolder is destroyed.
+TEST_F(PerContextDataTest, LookupAndDestruction) {
+ v8::Isolate::Scope isolate_scope(instance_->isolate());
+ v8::HandleScope handle_scope(instance_->isolate());
+ v8::Handle<v8::Context> context = v8::Context::New(
+ instance_->isolate(), NULL, v8::Handle<v8::ObjectTemplate>());
+ {
+ ContextHolder context_holder(instance_->isolate());
+ context_holder.SetContext(context);
+ PerContextData* per_context_data = PerContextData::From(context);
+ EXPECT_TRUE(per_context_data != NULL);
+ EXPECT_EQ(&context_holder, per_context_data->context_holder());
+ }
+ PerContextData* per_context_data = PerContextData::From(context);
+ EXPECT_TRUE(per_context_data == NULL);
+}
+
+} // namespace gin
diff --git a/chromium/gin/per_isolate_data.cc b/chromium/gin/per_isolate_data.cc
index 6c2397ba50b..99c928cdd8e 100644
--- a/chromium/gin/per_isolate_data.cc
+++ b/chromium/gin/per_isolate_data.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "gin/per_isolate_data.h"
#include "gin/public/gin_embedders.h"
+using v8::ArrayBuffer;
using v8::Eternal;
using v8::Isolate;
using v8::Local;
@@ -14,8 +17,11 @@ using v8::ObjectTemplate;
namespace gin {
-PerIsolateData::PerIsolateData(Isolate* isolate)
- : isolate_(isolate) {
+PerIsolateData::PerIsolateData(Isolate* isolate,
+ ArrayBuffer::Allocator* allocator)
+ : isolate_(isolate),
+ allocator_(allocator),
+ message_loop_proxy_(base::MessageLoopProxy::current()) {
isolate_->SetData(kEmbedderNativeGin, this);
}
@@ -53,4 +59,54 @@ v8::Local<v8::FunctionTemplate> PerIsolateData::GetFunctionTemplate(
return it->second.Get(isolate_);
}
+void PerIsolateData::SetIndexedPropertyInterceptor(
+ WrappableBase* base,
+ IndexedPropertyInterceptor* interceptor) {
+ indexed_interceptors_[base] = interceptor;
+}
+
+void PerIsolateData::SetNamedPropertyInterceptor(
+ WrappableBase* base,
+ NamedPropertyInterceptor* interceptor) {
+ named_interceptors_[base] = interceptor;
+}
+
+void PerIsolateData::ClearIndexedPropertyInterceptor(
+ WrappableBase* base,
+ IndexedPropertyInterceptor* interceptor) {
+ IndexedPropertyInterceptorMap::iterator it = indexed_interceptors_.find(base);
+ if (it != indexed_interceptors_.end())
+ indexed_interceptors_.erase(it);
+ else
+ NOTREACHED();
+}
+
+void PerIsolateData::ClearNamedPropertyInterceptor(
+ WrappableBase* base,
+ NamedPropertyInterceptor* interceptor) {
+ NamedPropertyInterceptorMap::iterator it = named_interceptors_.find(base);
+ if (it != named_interceptors_.end())
+ named_interceptors_.erase(it);
+ else
+ NOTREACHED();
+}
+
+IndexedPropertyInterceptor* PerIsolateData::GetIndexedPropertyInterceptor(
+ WrappableBase* base) {
+ IndexedPropertyInterceptorMap::iterator it = indexed_interceptors_.find(base);
+ if (it != indexed_interceptors_.end())
+ return it->second;
+ else
+ return NULL;
+}
+
+NamedPropertyInterceptor* PerIsolateData::GetNamedPropertyInterceptor(
+ WrappableBase* base) {
+ NamedPropertyInterceptorMap::iterator it = named_interceptors_.find(base);
+ if (it != named_interceptors_.end())
+ return it->second;
+ else
+ return NULL;
+}
+
} // namespace gin
diff --git a/chromium/gin/per_isolate_data.h b/chromium/gin/per_isolate_data.h
index ed935454749..bffe5fb2c6f 100644
--- a/chromium/gin/per_isolate_data.h
+++ b/chromium/gin/per_isolate_data.h
@@ -8,17 +8,26 @@
#include <map>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "gin/gin_export.h"
#include "gin/public/wrapper_info.h"
#include "v8/include/v8.h"
+namespace base {
+class MessageLoopProxy;
+}
+
namespace gin {
+class IndexedPropertyInterceptor;
+class NamedPropertyInterceptor;
+class WrappableBase;
+
// There is one instance of PerIsolateData per v8::Isolate managed by Gin. This
// class stores all the Gin-related data that varies per isolate.
class GIN_EXPORT PerIsolateData {
public:
- explicit PerIsolateData(v8::Isolate* isolate);
+ PerIsolateData(v8::Isolate* isolate, v8::ArrayBuffer::Allocator* allocator);
~PerIsolateData();
static PerIsolateData* From(v8::Isolate* isolate);
@@ -38,19 +47,47 @@ class GIN_EXPORT PerIsolateData {
v8::Local<v8::ObjectTemplate> GetObjectTemplate(WrapperInfo* info);
v8::Local<v8::FunctionTemplate> GetFunctionTemplate(WrapperInfo* info);
+ // We maintain a map from Wrappable objects that derive from one of the
+ // interceptor interfaces to the interceptor interface pointers.
+ void SetIndexedPropertyInterceptor(WrappableBase* base,
+ IndexedPropertyInterceptor* interceptor);
+ void SetNamedPropertyInterceptor(WrappableBase* base,
+ NamedPropertyInterceptor* interceptor);
+
+ void ClearIndexedPropertyInterceptor(WrappableBase* base,
+ IndexedPropertyInterceptor* interceptor);
+ void ClearNamedPropertyInterceptor(WrappableBase* base,
+ NamedPropertyInterceptor* interceptor);
+
+ IndexedPropertyInterceptor* GetIndexedPropertyInterceptor(
+ WrappableBase* base);
+ NamedPropertyInterceptor* GetNamedPropertyInterceptor(WrappableBase* base);
+
v8::Isolate* isolate() { return isolate_; }
+ v8::ArrayBuffer::Allocator* allocator() { return allocator_; }
+ base::MessageLoopProxy* message_loop_proxy() {
+ return message_loop_proxy_.get();
+ }
private:
typedef std::map<
WrapperInfo*, v8::Eternal<v8::ObjectTemplate> > ObjectTemplateMap;
typedef std::map<
WrapperInfo*, v8::Eternal<v8::FunctionTemplate> > FunctionTemplateMap;
+ typedef std::map<WrappableBase*, IndexedPropertyInterceptor*>
+ IndexedPropertyInterceptorMap;
+ typedef std::map<WrappableBase*, NamedPropertyInterceptor*>
+ NamedPropertyInterceptorMap;
// PerIsolateData doesn't actually own |isolate_|. Instead, the isolate is
// owned by the IsolateHolder, which also owns the PerIsolateData.
v8::Isolate* isolate_;
+ v8::ArrayBuffer::Allocator* allocator_;
ObjectTemplateMap object_templates_;
FunctionTemplateMap function_templates_;
+ IndexedPropertyInterceptorMap indexed_interceptors_;
+ NamedPropertyInterceptorMap named_interceptors_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
DISALLOW_COPY_AND_ASSIGN(PerIsolateData);
};
diff --git a/chromium/gin/public/context_holder.h b/chromium/gin/public/context_holder.h
index 09fe248a373..afbcf23d739 100644
--- a/chromium/gin/public/context_holder.h
+++ b/chromium/gin/public/context_holder.h
@@ -25,9 +25,7 @@ enum ContextEmbedderDataFields {
class PerContextData;
-// ContextHolder is a generic class for holding a v8::Context. Rather than
-// using ContextHolder directly, most code should use a subclass of
-// ContextHolder, such as Runner.
+// ContextHolder is a generic class for holding a v8::Context.
class GIN_EXPORT ContextHolder {
public:
explicit ContextHolder(v8::Isolate* isolate);
@@ -43,7 +41,7 @@ class GIN_EXPORT ContextHolder {
private:
v8::Isolate* isolate_;
- v8::Persistent<v8::Context> context_;
+ v8::UniquePersistent<v8::Context> context_;
scoped_ptr<PerContextData> data_;
DISALLOW_COPY_AND_ASSIGN(ContextHolder);
diff --git a/chromium/gin/public/isolate_holder.h b/chromium/gin/public/isolate_holder.h
index d68e4d5a58b..ee696f6550b 100644
--- a/chromium/gin/public/isolate_holder.h
+++ b/chromium/gin/public/isolate_holder.h
@@ -8,10 +8,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "gin/gin_export.h"
-
-namespace v8 {
-class Isolate;
-}
+#include "v8/include/v8.h"
namespace gin {
@@ -19,25 +16,31 @@ class PerIsolateData;
// To embed Gin, first create an instance of IsolateHolder to hold the
// v8::Isolate in which you will execute JavaScript. You might wish to subclass
-// IsolateHolder if you want to tie more state to the lifetime of the
+// IsolateHolder if you want to tie more state to the lifetime of the isolate.
//
// You can use gin in two modes: either gin manages V8, or the gin-embedder
-// manages gin. If gin manages V8, use the IsolateHolder constructor without
-// parameters, otherwise, the gin-embedder needs to create v8::Isolates and
-// pass them to IsolateHolder.
+// manages gin. If gin manages V8, use the IsolateHolder constructor that does
+// not take an v8::Isolate parameter, otherwise, the gin-embedder needs to
+// create v8::Isolates and pass them to IsolateHolder.
//
// It is not possible to mix the two.
class GIN_EXPORT IsolateHolder {
public:
- IsolateHolder();
- explicit IsolateHolder(v8::Isolate* isolate);
+ // Controls whether or not V8 should only accept strict mode scripts.
+ enum ScriptMode {
+ kNonStrictMode,
+ kStrictMode
+ };
+
+ explicit IsolateHolder(ScriptMode mode);
+ IsolateHolder(v8::Isolate* isolate, v8::ArrayBuffer::Allocator* allocator);
~IsolateHolder();
v8::Isolate* isolate() { return isolate_; }
private:
- void Init();
+ void Init(v8::ArrayBuffer::Allocator* allocator);
bool isolate_owner_;
v8::Isolate* isolate_;
diff --git a/chromium/gin/public/v8_platform.h b/chromium/gin/public/v8_platform.h
new file mode 100644
index 00000000000..2df0f848e59
--- /dev/null
+++ b/chromium/gin/public/v8_platform.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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_PUBLIC_V8_PLATFORM_H_
+#define GIN_PUBLIC_V8_PLATFORM_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "gin/gin_export.h"
+#include "v8/include/v8-platform.h"
+
+namespace gin {
+
+// A v8::Platform implementation to use with gin.
+class GIN_EXPORT V8Platform : public NON_EXPORTED_BASE(v8::Platform) {
+ public:
+ static V8Platform* Get();
+
+ // v8::Platform implementation.
+ virtual void CallOnBackgroundThread(
+ v8::Task* task,
+ v8::Platform::ExpectedRuntime expected_runtime) OVERRIDE;
+ virtual void CallOnForegroundThread(v8::Isolate* isolate,
+ v8::Task* task) OVERRIDE;
+ private:
+ friend struct base::DefaultLazyInstanceTraits<V8Platform>;
+
+ V8Platform();
+ virtual ~V8Platform();
+
+ DISALLOW_COPY_AND_ASSIGN(V8Platform);
+};
+
+} // namespace gin
+
+#endif // GIN_PUBLIC_V8_PLATFORM_H_
diff --git a/chromium/gin/runner.cc b/chromium/gin/runner.cc
index 37e16a09c74..6f018b165b2 100644
--- a/chromium/gin/runner.cc
+++ b/chromium/gin/runner.cc
@@ -4,96 +4,18 @@
#include "gin/runner.h"
-#include "gin/converter.h"
-#include "gin/per_context_data.h"
-#include "gin/try_catch.h"
-
-using v8::Context;
-using v8::HandleScope;
-using v8::Isolate;
-using v8::Object;
-using v8::ObjectTemplate;
-using v8::Script;
-
namespace gin {
-RunnerDelegate::RunnerDelegate() {
-}
-
-RunnerDelegate::~RunnerDelegate() {
-}
-
-v8::Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) {
- return v8::Handle<ObjectTemplate>();
-}
-
-void RunnerDelegate::DidCreateContext(Runner* runner) {
-}
-
-void RunnerDelegate::WillRunScript(Runner* runner) {
-}
-
-void RunnerDelegate::DidRunScript(Runner* runner) {
-}
-
-void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) {
-}
-
-Runner::Runner(RunnerDelegate* delegate, Isolate* isolate)
- : ContextHolder(isolate),
- delegate_(delegate),
- weak_factory_(this) {
- v8::Isolate::Scope isolate_scope(isolate);
- HandleScope handle_scope(isolate);
- v8::Handle<v8::Context> context =
- Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this));
-
- SetContext(context);
- PerContextData::From(context)->set_runner(this);
-
- v8::Context::Scope scope(context);
- delegate_->DidCreateContext(this);
+Runner::Runner() : weak_factory_(this) {
}
Runner::~Runner() {
}
-void Runner::Run(const std::string& source, const std::string& resource_name) {
- Run(Script::New(StringToV8(isolate(), source),
- StringToV8(isolate(), resource_name)));
-}
-
-void Runner::Run(v8::Handle<Script> script) {
- TryCatch try_catch;
- delegate_->WillRunScript(this);
-
- script->Run();
-
- delegate_->DidRunScript(this);
- if (try_catch.HasCaught())
- delegate_->UnhandledException(this, try_catch);
-}
-
-v8::Handle<v8::Value> Runner::Call(v8::Handle<v8::Function> function,
- v8::Handle<v8::Value> receiver,
- int argc,
- v8::Handle<v8::Value> argv[]) {
- TryCatch try_catch;
- delegate_->WillRunScript(this);
-
- v8::Handle<v8::Value> result = function->Call(receiver, argc, argv);
-
- delegate_->DidRunScript(this);
- if (try_catch.HasCaught())
- delegate_->UnhandledException(this, try_catch);
-
- return result;
-}
-
Runner::Scope::Scope(Runner* runner)
- : isolate_scope_(runner->isolate()),
- handle_scope_(runner->isolate()),
- scope_(runner->context()) {
+ : isolate_scope_(runner->GetContextHolder()->isolate()),
+ handle_scope_(runner->GetContextHolder()->isolate()),
+ scope_(runner->GetContextHolder()->context()) {
}
Runner::Scope::~Scope() {
diff --git a/chromium/gin/runner.h b/chromium/gin/runner.h
index 943bcedba1c..36a75d2f956 100644
--- a/chromium/gin/runner.h
+++ b/chromium/gin/runner.h
@@ -10,47 +10,28 @@
#include "base/memory/weak_ptr.h"
#include "gin/gin_export.h"
#include "gin/public/context_holder.h"
+#include "v8/include/v8.h"
namespace gin {
-class Runner;
-class TryCatch;
-
-// Subclass RunnerDelegate to customize the behavior of |Runner|. Typical
-// embedders will want to subclass one of the specialized RunnerDelegates,
-// such as ModuleRunnerDelegate.
-class GIN_EXPORT RunnerDelegate {
- public:
- RunnerDelegate();
- virtual ~RunnerDelegate();
-
- // Returns the template for the global object.
- virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(Runner* runner);
- virtual void DidCreateContext(Runner* runner);
- virtual void WillRunScript(Runner* runner);
- virtual void DidRunScript(Runner* runner);
- virtual void UnhandledException(Runner* runner, TryCatch& try_catch);
-};
-
-// Runner lets you run code in a v8::Context. Upon construction, Runner will
-// create a v8::Context. Upon destruction, Runner will dispose the context.
-class GIN_EXPORT Runner : public ContextHolder {
+// Runner is responsible for running code in a v8::Context.
+class GIN_EXPORT Runner {
public:
- Runner(RunnerDelegate* delegate, v8::Isolate* isolate);
- ~Runner();
+ Runner();
+ virtual ~Runner();
// Before running script in this context, you'll need to enter the runner's
// context by creating an instance of Runner::Scope on the stack.
- void Run(const std::string& source, const std::string& resource_name);
- void Run(v8::Handle<v8::Script> script);
-
- v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function,
- v8::Handle<v8::Value> receiver,
- int argc,
- v8::Handle<v8::Value> argv[]);
-
- v8::Handle<v8::Object> global() const {
- return context()->Global();
+ virtual void Run(const std::string& source,
+ const std::string& resource_name) = 0;
+ virtual v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Value> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]) = 0;
+ virtual ContextHolder* GetContextHolder() = 0;
+
+ v8::Handle<v8::Object> global() {
+ return GetContextHolder()->context()->Global();
}
// Useful for running script in this context asynchronously. Rather than
@@ -75,8 +56,6 @@ class GIN_EXPORT Runner : public ContextHolder {
private:
friend class Scope;
- RunnerDelegate* delegate_;
-
base::WeakPtrFactory<Runner> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Runner);
diff --git a/chromium/gin/shell/gin_main.cc b/chromium/gin/shell/gin_main.cc
index 24fa6df1528..8fc946502d5 100644
--- a/chromium/gin/shell/gin_main.cc
+++ b/chromium/gin/shell/gin_main.cc
@@ -33,17 +33,17 @@ void Run(base::WeakPtr<Runner> runner, const base::FilePath& path) {
std::vector<base::FilePath> GetModuleSearchPaths() {
std::vector<base::FilePath> module_base(1);
- CHECK(file_util::GetCurrentDirectory(&module_base[0]));
+ CHECK(base::GetCurrentDirectory(&module_base[0]));
return module_base;
}
class ShellRunnerDelegate : public ModuleRunnerDelegate {
public:
ShellRunnerDelegate() : ModuleRunnerDelegate(GetModuleSearchPaths()) {
- AddBuiltinModule(Console::kModuleName, Console::GetTemplate);
+ AddBuiltinModule(Console::kModuleName, Console::GetModule);
}
- virtual void UnhandledException(Runner* runner,
+ virtual void UnhandledException(ShellRunner* runner,
TryCatch& try_catch) OVERRIDE {
ModuleRunnerDelegate::UnhandledException(runner, try_catch);
LOG(ERROR) << try_catch.GetStackTrace();
@@ -61,12 +61,12 @@ int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
base::i18n::InitializeICU();
- gin::IsolateHolder instance;
+ gin::IsolateHolder instance(gin::IsolateHolder::kStrictMode);
base::MessageLoop message_loop;
gin::ShellRunnerDelegate delegate;
- gin::Runner runner(&delegate, instance.isolate());
+ gin::ShellRunner runner(&delegate, instance.isolate());
{
gin::Runner::Scope scope(&runner);
diff --git a/chromium/gin/shell_runner.cc b/chromium/gin/shell_runner.cc
new file mode 100644
index 00000000000..8d98e425d74
--- /dev/null
+++ b/chromium/gin/shell_runner.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 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/shell_runner.h"
+
+#include "gin/converter.h"
+#include "gin/modules/module_registry.h"
+#include "gin/per_context_data.h"
+#include "gin/public/context_holder.h"
+#include "gin/try_catch.h"
+
+using v8::Context;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Script;
+
+namespace gin {
+
+ShellRunnerDelegate::ShellRunnerDelegate() {
+}
+
+ShellRunnerDelegate::~ShellRunnerDelegate() {
+}
+
+v8::Handle<ObjectTemplate> ShellRunnerDelegate::GetGlobalTemplate(
+ ShellRunner* runner,
+ v8::Isolate* isolate) {
+ return v8::Handle<ObjectTemplate>();
+}
+
+void ShellRunnerDelegate::DidCreateContext(ShellRunner* runner) {
+}
+
+void ShellRunnerDelegate::WillRunScript(ShellRunner* runner) {
+}
+
+void ShellRunnerDelegate::DidRunScript(ShellRunner* runner) {
+}
+
+void ShellRunnerDelegate::UnhandledException(ShellRunner* runner,
+ TryCatch& try_catch) {
+ CHECK(false) << try_catch.GetStackTrace();
+}
+
+ShellRunner::ShellRunner(ShellRunnerDelegate* delegate, Isolate* isolate)
+ : delegate_(delegate) {
+ v8::Isolate::Scope isolate_scope(isolate);
+ HandleScope handle_scope(isolate);
+ v8::Handle<v8::Context> context =
+ Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this, isolate));
+
+ context_holder_.reset(new ContextHolder(isolate));
+ context_holder_->SetContext(context);
+ PerContextData::From(context)->set_runner(this);
+
+ v8::Context::Scope scope(context);
+ delegate_->DidCreateContext(this);
+}
+
+ShellRunner::~ShellRunner() {
+}
+
+void ShellRunner::Run(const std::string& source,
+ const std::string& resource_name) {
+ TryCatch try_catch;
+ v8::Isolate* isolate = GetContextHolder()->isolate();
+ v8::Handle<Script> script = Script::Compile(
+ StringToV8(isolate, source), StringToV8(isolate, resource_name));
+ if (try_catch.HasCaught()) {
+ delegate_->UnhandledException(this, try_catch);
+ return;
+ }
+
+ Run(script);
+}
+
+v8::Handle<v8::Value> ShellRunner::Call(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Value> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]) {
+ TryCatch try_catch;
+ delegate_->WillRunScript(this);
+
+ v8::Handle<v8::Value> result = function->Call(receiver, argc, argv);
+
+ delegate_->DidRunScript(this);
+ if (try_catch.HasCaught())
+ delegate_->UnhandledException(this, try_catch);
+
+ return result;
+}
+
+ContextHolder* ShellRunner::GetContextHolder() {
+ return context_holder_.get();
+}
+
+void ShellRunner::Run(v8::Handle<Script> script) {
+ TryCatch try_catch;
+ delegate_->WillRunScript(this);
+
+ script->Run();
+
+ delegate_->DidRunScript(this);
+ if (try_catch.HasCaught()) {
+ delegate_->UnhandledException(this, try_catch);
+ }
+}
+
+} // namespace gin
diff --git a/chromium/gin/shell_runner.h b/chromium/gin/shell_runner.h
new file mode 100644
index 00000000000..645bc8e6df1
--- /dev/null
+++ b/chromium/gin/shell_runner.h
@@ -0,0 +1,68 @@
+// Copyright 2014 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_SHELL_RUNNER_H_
+#define GIN_SHELL_RUNNER_H_
+
+#include "gin/runner.h"
+
+namespace gin {
+
+class ContextHolder;
+class ShellRunner;
+class TryCatch;
+
+// Subclass ShellRunnerDelegate to customize the behavior of ShellRunner.
+// Typical embedders will want to subclass one of the specialized
+// ShellRunnerDelegates, such as ModuleRunnerDelegate.
+class GIN_EXPORT ShellRunnerDelegate {
+ public:
+ ShellRunnerDelegate();
+ virtual ~ShellRunnerDelegate();
+
+ // Returns the template for the global object.
+ virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
+ ShellRunner* runner,
+ v8::Isolate* isolate);
+ virtual void DidCreateContext(ShellRunner* runner);
+ virtual void WillRunScript(ShellRunner* runner);
+ virtual void DidRunScript(ShellRunner* runner);
+ virtual void UnhandledException(ShellRunner* runner, TryCatch& try_catch);
+};
+
+// ShellRunner executes the script/functions directly in a v8::Context.
+// ShellRunner owns a ContextHolder and v8::Context, both of which are destroyed
+// when the ShellRunner is deleted.
+class GIN_EXPORT ShellRunner : public Runner {
+ public:
+ ShellRunner(ShellRunnerDelegate* delegate, v8::Isolate* isolate);
+ virtual ~ShellRunner();
+
+ // Before running script in this context, you'll need to enter the runner's
+ // context by creating an instance of Runner::Scope on the stack.
+
+ // Runner overrides:
+ virtual void Run(const std::string& source,
+ const std::string& resource_name) OVERRIDE;
+ virtual v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Value> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]) OVERRIDE;
+ virtual ContextHolder* GetContextHolder() OVERRIDE;
+
+ private:
+ friend class Scope;
+
+ void Run(v8::Handle<v8::Script> script);
+
+ ShellRunnerDelegate* delegate_;
+
+ scoped_ptr<ContextHolder> context_holder_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellRunner);
+};
+
+} // namespace gin
+
+#endif // GIN_SHELL_RUNNER_H_
diff --git a/chromium/gin/runner_unittest.cc b/chromium/gin/shell_runner_unittest.cc
index 3723956df6a..95403ecf06d 100644
--- a/chromium/gin/runner_unittest.cc
+++ b/chromium/gin/shell_runner_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2014 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/runner.h"
+#include "gin/shell_runner.h"
#include "base/compiler_specific.h"
#include "gin/converter.h"
@@ -19,11 +19,11 @@ namespace gin {
TEST(RunnerTest, Run) {
std::string source = "this.result = 'PASS';\n";
- gin::IsolateHolder instance;
+ gin::IsolateHolder instance(gin::IsolateHolder::kStrictMode);
- RunnerDelegate delegate;
+ ShellRunnerDelegate delegate;
Isolate* isolate = instance.isolate();
- Runner runner(&delegate, isolate);
+ ShellRunner runner(&delegate, isolate);
Runner::Scope scope(&runner);
runner.Run(source, "test_data.js");
diff --git a/chromium/gin/v8_platform.cc b/chromium/gin/v8_platform.cc
new file mode 100644
index 00000000000..d50ff24f8bf
--- /dev/null
+++ b/chromium/gin/v8_platform.cc
@@ -0,0 +1,42 @@
+// Copyright 2014 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/public/v8_platform.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/threading/worker_pool.h"
+#include "gin/per_isolate_data.h"
+
+namespace gin {
+
+namespace {
+
+base::LazyInstance<V8Platform>::Leaky g_v8_platform = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// static
+V8Platform* V8Platform::Get() { return g_v8_platform.Pointer(); }
+
+V8Platform::V8Platform() {}
+
+V8Platform::~V8Platform() {}
+
+void V8Platform::CallOnBackgroundThread(
+ v8::Task* task,
+ v8::Platform::ExpectedRuntime expected_runtime) {
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&v8::Task::Run, base::Owned(task)),
+ expected_runtime == v8::Platform::kLongRunningTask);
+}
+
+void V8Platform::CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) {
+ PerIsolateData::From(isolate)->message_loop_proxy()->PostTask(
+ FROM_HERE, base::Bind(&v8::Task::Run, base::Owned(task)));
+}
+
+} // namespace gin
diff --git a/chromium/gin/wrappable.cc b/chromium/gin/wrappable.cc
index 4a9ef0e1935..a330fefc8e8 100644
--- a/chromium/gin/wrappable.cc
+++ b/chromium/gin/wrappable.cc
@@ -5,6 +5,7 @@
#include "gin/wrappable.h"
#include "base/logging.h"
+#include "gin/object_template_builder.h"
#include "gin/per_isolate_data.h"
namespace gin {
@@ -16,11 +17,9 @@ WrappableBase::~WrappableBase() {
wrapper_.Reset();
}
-v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(
- v8::Isolate* isolate, WrapperInfo* wrapper_info) {
- if (wrapper_.IsEmpty())
- CreateWrapper(isolate, wrapper_info);
- return v8::Local<v8::Object>::New(isolate, wrapper_);
+ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder(
+ v8::Isolate* isolate) {
+ return ObjectTemplateBuilder(isolate);
}
void WrappableBase::WeakCallback(
@@ -30,13 +29,29 @@ void WrappableBase::WeakCallback(
delete wrappable;
}
-v8::Handle<v8::Object> WrappableBase::CreateWrapper(v8::Isolate* isolate,
- WrapperInfo* info) {
+v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
+ WrapperInfo* info) {
+ if (!wrapper_.IsEmpty()) {
+ return v8::Local<v8::Object>::New(isolate, wrapper_);
+ }
+
PerIsolateData* data = PerIsolateData::From(isolate);
v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info);
- CHECK(!templ.IsEmpty()); // Don't forget to register an object template.
+ if (templ.IsEmpty()) {
+ templ = GetObjectTemplateBuilder(isolate).Build();
+ CHECK(!templ.IsEmpty());
+ data->SetObjectTemplate(info, templ);
+ }
CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount());
v8::Handle<v8::Object> wrapper = templ->NewInstance();
+ // |wrapper| may be empty in some extreme cases, e.g., when
+ // Object.prototype.constructor is overwritten.
+ if (wrapper.IsEmpty()) {
+ // The current wrappable object will be no longer managed by V8. Delete this
+ // now.
+ delete this;
+ return wrapper;
+ }
wrapper->SetAlignedPointerInInternalField(kWrapperInfoIndex, info);
wrapper->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
wrapper_.Reset(isolate, wrapper);
diff --git a/chromium/gin/wrappable.h b/chromium/gin/wrappable.h
index 755707166bb..ff52b19a06f 100644
--- a/chromium/gin/wrappable.h
+++ b/chromium/gin/wrappable.h
@@ -27,11 +27,23 @@ GIN_EXPORT void* FromV8Impl(v8::Isolate* isolate,
// USAGE:
// // my_class.h
// class MyClass : Wrappable<MyClass> {
+// public:
+// static WrapperInfo kWrapperInfo;
+//
+// // Optional, only required if non-empty template should be used.
+// virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+// v8::Isolate* isolate);
// ...
// };
//
// // my_class.cc
-// INIT_WRAPABLE(MyClass);
+// WrapperInfo MyClass::kWrapperInfo = {kEmbedderNativeGin};
+//
+// gin::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder(
+// v8::Isolate* isolate) {
+// return Wrappable<MyClass>::GetObjectTemplateBuilder(isolate)
+// .SetValue("foobar", 42);
+// }
//
// Subclasses should also typically have private constructors and expose a
// static Create function that returns a gin::Handle. Forcing creators through
@@ -42,22 +54,25 @@ GIN_EXPORT void* FromV8Impl(v8::Isolate* isolate,
template<typename T>
class Wrappable;
+class ObjectTemplateBuilder;
// Non-template base class to share code between templates instances.
class GIN_EXPORT WrappableBase {
protected:
WrappableBase();
virtual ~WrappableBase();
+
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
+
v8::Handle<v8::Object> GetWrapperImpl(v8::Isolate* isolate,
WrapperInfo* wrapper_info);
- v8::Handle<v8::Object> CreateWrapper(v8::Isolate* isolate,
- WrapperInfo* wrapper_info);
- v8::Persistent<v8::Object> wrapper_; // Weak
private:
static void WeakCallback(
const v8::WeakCallbackData<v8::Object, WrappableBase>& data);
+ v8::Persistent<v8::Object> wrapper_; // Weak
+
DISALLOW_COPY_AND_ASSIGN(WrappableBase);
};
@@ -84,14 +99,14 @@ class Wrappable : public WrappableBase {
// This converter handles any subclass of Wrappable.
template<typename T>
struct Converter<T*, typename base::enable_if<
- base::is_convertible<T*, Wrappable<T>*>::value>::type> {
+ base::is_convertible<T*, WrappableBase*>::value>::type> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
return val->GetWrapper(isolate);
}
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) {
- *out = static_cast<T*>(internal::FromV8Impl(isolate, val,
- &T::kWrapperInfo));
+ *out = static_cast<T*>(static_cast<WrappableBase*>(
+ internal::FromV8Impl(isolate, val, &T::kWrapperInfo)));
return *out != NULL;
}
};
diff --git a/chromium/gin/wrappable_unittest.cc b/chromium/gin/wrappable_unittest.cc
index 3499eedcc18..4916153be52 100644
--- a/chromium/gin/wrappable_unittest.cc
+++ b/chromium/gin/wrappable_unittest.cc
@@ -15,7 +15,19 @@
namespace gin {
-class MyObject : public Wrappable<MyObject> {
+class BaseClass {
+ public:
+ BaseClass() : value_(23) {}
+ virtual ~BaseClass() {}
+
+ private:
+ int value_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseClass);
+};
+
+class MyObject : public BaseClass,
+ public Wrappable<MyObject> {
public:
static WrapperInfo kWrapperInfo;
@@ -26,13 +38,72 @@ class MyObject : public Wrappable<MyObject> {
int value() const { return value_; }
void set_value(int value) { value_ = value; }
- private:
+ protected:
MyObject() : value_(0) {}
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE;
virtual ~MyObject() {}
+ private:
int value_;
};
+class MyObjectSubclass : public MyObject {
+ public:
+ static gin::Handle<MyObjectSubclass> Create(v8::Isolate* isolate) {
+ return CreateHandle(isolate, new MyObjectSubclass());
+ }
+
+ void SayHello(const std::string& name) {
+ result = std::string("Hello, ") + name;
+ }
+
+ std::string result;
+
+ private:
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE {
+ return MyObject::GetObjectTemplateBuilder(isolate)
+ .SetMethod("sayHello", &MyObjectSubclass::SayHello);
+ }
+
+ MyObjectSubclass() {
+ }
+
+ virtual ~MyObjectSubclass() {
+ }
+};
+
+class MyCallableObject : public Wrappable<MyCallableObject> {
+ public:
+ static WrapperInfo kWrapperInfo;
+
+ static gin::Handle<MyCallableObject> Create(v8::Isolate* isolate) {
+ return CreateHandle(isolate, new MyCallableObject());
+ }
+
+ int result() { return result_; }
+
+ private:
+ virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE {
+ return Wrappable<MyCallableObject>::GetObjectTemplateBuilder(isolate)
+ .SetCallAsFunctionHandler(&MyCallableObject::Call);
+ }
+
+ MyCallableObject() : result_(0) {
+ }
+
+ virtual ~MyCallableObject() {
+ }
+
+ void Call(int val) {
+ result_ = val;
+ }
+
+ int result_;
+};
+
class MyObject2 : public Wrappable<MyObject2> {
public:
static WrapperInfo kWrapperInfo;
@@ -44,35 +115,21 @@ class MyObjectBlink : public Wrappable<MyObjectBlink> {
};
WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin };
+ObjectTemplateBuilder MyObject::GetObjectTemplateBuilder(v8::Isolate* isolate) {
+ return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate)
+ .SetProperty("value", &MyObject::value, &MyObject::set_value);
+}
+
+WrapperInfo MyCallableObject::kWrapperInfo = { kEmbedderNativeGin };
WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin };
WrapperInfo MyObjectBlink::kWrapperInfo = { kEmbedderNativeGin };
-void RegisterTemplates(v8::Isolate* isolate) {
- PerIsolateData* data = PerIsolateData::From(isolate);
- DCHECK(data->GetObjectTemplate(&MyObject::kWrapperInfo).IsEmpty());
-
- v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate)
- .SetProperty("value", &MyObject::value, &MyObject::set_value)
- .Build();
- templ->SetInternalFieldCount(kNumberOfInternalFields);
- data->SetObjectTemplate(&MyObject::kWrapperInfo, templ);
-
- templ = v8::ObjectTemplate::New(isolate);
- templ->SetInternalFieldCount(kNumberOfInternalFields);
- data->SetObjectTemplate(&MyObject2::kWrapperInfo, templ);
-
- templ = v8::ObjectTemplate::New(isolate);
- templ->SetInternalFieldCount(kNumberOfInternalFields);
- data->SetObjectTemplate(&MyObjectBlink::kWrapperInfo, templ);
-}
-
typedef V8Test WrappableTest;
TEST_F(WrappableTest, WrapAndUnwrap) {
v8::Isolate* isolate = instance_->isolate();
v8::HandleScope handle_scope(isolate);
- RegisterTemplates(isolate);
Handle<MyObject> obj = MyObject::Create(isolate);
v8::Handle<v8::Value> wrapper = ConvertToV8(isolate, obj.get());
@@ -87,10 +144,8 @@ TEST_F(WrappableTest, UnwrapFailures) {
v8::Isolate* isolate = instance_->isolate();
v8::HandleScope handle_scope(isolate);
- RegisterTemplates(isolate);
-
// Something that isn't an object.
- v8::Handle<v8::Value> thing = v8::Number::New(42);
+ v8::Handle<v8::Value> thing = v8::Number::New(isolate, 42);
MyObject* unwrapped = NULL;
EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
EXPECT_FALSE(unwrapped);
@@ -117,7 +172,6 @@ TEST_F(WrappableTest, GetAndSetProperty) {
v8::Isolate* isolate = instance_->isolate();
v8::HandleScope handle_scope(isolate);
- RegisterTemplates(isolate);
gin::Handle<MyObject> obj = MyObject::Create(isolate);
obj->set_value(42);
@@ -130,7 +184,7 @@ TEST_F(WrappableTest, GetAndSetProperty) {
EXPECT_FALSE(source.IsEmpty());
gin::TryCatch try_catch;
- v8::Handle<v8::Script> script = v8::Script::New(source);
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
EXPECT_FALSE(script.IsEmpty());
v8::Handle<v8::Value> val = script->Run();
EXPECT_FALSE(val.IsEmpty());
@@ -146,4 +200,71 @@ TEST_F(WrappableTest, GetAndSetProperty) {
EXPECT_EQ(191, obj->value());
}
+TEST_F(WrappableTest, WrappableSubclass) {
+ v8::Isolate* isolate = instance_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ gin::Handle<MyObjectSubclass> object(MyObjectSubclass::Create(isolate));
+ v8::Handle<v8::String> source = StringToV8(isolate,
+ "(function(obj) {"
+ "obj.sayHello('Lily');"
+ "})");
+ gin::TryCatch try_catch;
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+ v8::Handle<v8::Value> val = script->Run();
+ v8::Handle<v8::Function> func;
+ EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
+ v8::Handle<v8::Value> argv[] = {
+ ConvertToV8(isolate, object.get())
+ };
+ func->Call(v8::Undefined(isolate), 1, argv);
+ EXPECT_FALSE(try_catch.HasCaught());
+ EXPECT_EQ("Hello, Lily", object->result);
+}
+
+TEST_F(WrappableTest, ErrorInObjectConstructorProperty) {
+ v8::Isolate* isolate = instance_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Handle<v8::String> source = StringToV8(
+ isolate,
+ "(function() {"
+ " Object.defineProperty(Object.prototype, 'constructor', {"
+ " get: function() { throw 'Error'; },"
+ " set: function() { throw 'Error'; }"
+ " });"
+ "})();");
+ EXPECT_FALSE(source.IsEmpty());
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+ script->Run();
+
+ gin::TryCatch try_catch;
+ gin::Handle<MyObject> obj = MyObject::Create(isolate);
+ EXPECT_TRUE(obj.IsEmpty());
+ EXPECT_TRUE(try_catch.HasCaught());
+}
+
+TEST_F(WrappableTest, CallAsFunction) {
+ v8::Isolate* isolate = instance_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ gin::Handle<MyCallableObject> object(MyCallableObject::Create(isolate));
+ EXPECT_EQ(0, object->result());
+ v8::Handle<v8::String> source = StringToV8(isolate,
+ "(function(obj) {"
+ "obj(42);"
+ "})");
+ gin::TryCatch try_catch;
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+ v8::Handle<v8::Value> val = script->Run();
+ v8::Handle<v8::Function> func;
+ EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
+ v8::Handle<v8::Value> argv[] = {
+ ConvertToV8(isolate, object.get())
+ };
+ func->Call(v8::Undefined(isolate), 1, argv);
+ EXPECT_FALSE(try_catch.HasCaught());
+ EXPECT_EQ(42, object->result());
+}
+
} // namespace gin