summaryrefslogtreecommitdiffstats
path: root/gin
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-10 05:00:50 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-10 05:00:50 +0000
commita22998a223ecdcd926d152baea8a8703bcb57d61 (patch)
treeccb6b71bcc50b61c6671d955fbc409802f0c8d95 /gin
parent1cde19eb7e17b16645fb75a50f3250218d53cd17 (diff)
downloadchromium_src-a22998a223ecdcd926d152baea8a8703bcb57d61.zip
chromium_src-a22998a223ecdcd926d152baea8a8703bcb57d61.tar.gz
chromium_src-a22998a223ecdcd926d152baea8a8703bcb57d61.tar.bz2
This CL introduces a lightweight bindings system for V8 called gin
Unlike the extensions V8 bindings, gin is based on ObjectTemplates rather than on evaluating script. Unlike the Blink V8 bindings, gin isn't tightly coupled to Blink. In fact, gin's only link-time dependency is V8. We plan to use gin to build the V8 bindings for Mojo (see https://codereview.chromium.org/59153005/ for an example of how they will be used). In the long term, gin could serve as a basis for both the Blink and the extension system bindings, but we don't have any immediate plans to pursue that use of this code. This code is largely inspired by a lightweight bindings system designed by Aaron Boodman. Review URL: https://codereview.chromium.org/67763002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234160 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r--gin/DEPS7
-rw-r--r--gin/OWNERS2
-rw-r--r--gin/README8
-rw-r--r--gin/array_buffer.cc150
-rw-r--r--gin/array_buffer.h45
-rw-r--r--gin/converter.cc102
-rw-r--r--gin/converter.h121
-rw-r--r--gin/converter_unittest.cc128
-rw-r--r--gin/gin.gyp54
-rw-r--r--gin/initialize.cc38
-rw-r--r--gin/initialize.h14
-rw-r--r--gin/per_isolate_data.cc33
-rw-r--r--gin/per_isolate_data.h38
-rw-r--r--gin/runner.cc64
-rw-r--r--gin/runner.h67
-rw-r--r--gin/runner_unittest.cc55
-rw-r--r--gin/test/run_all_unittests.cc20
-rw-r--r--gin/test/v8_test.cc33
-rw-r--r--gin/test/v8_test.h30
-rw-r--r--gin/wrapper_info.cc16
-rw-r--r--gin/wrapper_info.h25
21 files changed, 1050 insertions, 0 deletions
diff --git a/gin/DEPS b/gin/DEPS
new file mode 100644
index 0000000..6e9bed8
--- /dev/null
+++ b/gin/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+v8",
+
+ # Use of base is allowed in tests. We can also use base in production code
+ # as long as we don't introduce a link-time dependency.
+ "+base",
+]
diff --git a/gin/OWNERS b/gin/OWNERS
new file mode 100644
index 0000000..98c7ef8
--- /dev/null
+++ b/gin/OWNERS
@@ -0,0 +1,2 @@
+aa@chromium.org
+abarth@chromium.org
diff --git a/gin/README b/gin/README
new file mode 100644
index 0000000..82d0618
--- /dev/null
+++ b/gin/README
@@ -0,0 +1,8 @@
+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.
diff --git a/gin/array_buffer.cc b/gin/array_buffer.cc
new file mode 100644
index 0000000..e8236fc
--- /dev/null
+++ b/gin/array_buffer.cc
@@ -0,0 +1,150 @@
+// 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/array_buffer.h"
+
+#include <stdlib.h>
+
+namespace gin {
+
+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) {
+ return calloc(1, length);
+}
+
+void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
+ return malloc(length);
+}
+
+void ArrayBufferAllocator::Free(void* data, size_t length) {
+ free(data);
+}
+
+ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
+ static ArrayBufferAllocator* instance = new ArrayBufferAllocator();
+ return instance;
+}
+
+// BufferView::Private --------------------------------------------------------
+
+// This class exists to solve a tricky lifetime problem. The V8 API doesn't
+// want to expose a direct view into the memory behind an array buffer because
+// V8 might deallocate that memory during garbage collection. Instead, the V8
+// API forces us to externalize the buffer and take ownership of the memory.
+// In order to know when to free the memory, we need to figure out both when
+// we're done with it and when V8 is done with it.
+//
+// To determine whether we're done with the memory, every view we have into
+// the array buffer takes a reference to the BufferView::Private object that
+// actually owns the memory. To determine when V8 is done with the memory, we
+// open a weak handle to the ArrayBuffer object. When we receive the weak
+// callback, we know the object is about to be garbage collected and we can
+// drop V8's implied reference to the memory.
+//
+// The final subtlety is that we need every BufferView into the same array
+// buffer to AddRef the same BufferView::Private. To make that work, we store a
+// pointer to the BufferView::Private object in an internal field of the
+// ArrayBuffer object.
+//
+class BufferView::Private {
+ public:
+ static scoped_refptr<Private> From(v8::Isolate* isolate,
+ v8::Handle<v8::ArrayBuffer> array);
+
+ void AddRef();
+ void Release();
+
+ void* buffer() const { return buffer_; }
+ size_t length() const { return length_; }
+
+ private:
+ Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array);
+ ~Private();
+
+ static void WeakCallback(
+ const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data);
+
+ size_t ref_count_;
+ v8::Persistent<v8::ArrayBuffer> array_buffer_;
+ void* buffer_;
+ size_t length_;
+};
+
+scoped_refptr<BufferView::Private> BufferView::Private::From(
+ v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) {
+ if (array->IsExternal()) {
+ return make_scoped_refptr(static_cast<Private*>(
+ array->GetAlignedPointerFromInternalField(kBufferViewPrivateIndex)));
+ }
+ return make_scoped_refptr(new Private(isolate, array));
+}
+
+void BufferView::Private::AddRef() {
+ ++ref_count_;
+}
+
+void BufferView::Private::Release() {
+ if (--ref_count_)
+ return;
+ delete this;
+}
+
+BufferView::Private::Private(v8::Isolate* isolate,
+ v8::Handle<v8::ArrayBuffer> array)
+ : ref_count_(0),
+ array_buffer_(isolate, array) {
+ // Take ownership of the array buffer.
+ v8::ArrayBuffer::Contents contents = array->Externalize();
+ buffer_ = contents.Data();
+ length_ = contents.ByteLength();
+
+ array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this);
+
+ AddRef(); // Balanced in WeakCallback.
+ array_buffer_.SetWeak(this, WeakCallback);
+}
+
+BufferView::Private::~Private() {
+ ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_);
+}
+
+void BufferView::Private::WeakCallback(
+ const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) {
+ Private* parameter = data.GetParameter();
+ parameter->array_buffer_.Reset();
+ parameter->Release(); // Balanced in BufferView::Private::Private.
+}
+
+// BufferView -----------------------------------------------------------------
+
+BufferView::BufferView(v8::Isolate* isolate,
+ v8::Handle<v8::ArrayBufferView> view) {
+ Initialize(isolate, view->Buffer());
+ uint8_t* ptr = static_cast<uint8_t*>(bytes_);
+ bytes_ = static_cast<void*>(ptr + view->ByteOffset());
+ num_bytes_ = view->ByteLength();
+}
+
+BufferView::BufferView(v8::Isolate* isolate,
+ v8::Handle<v8::ArrayBuffer> array) {
+ Initialize(isolate, array);
+}
+
+BufferView::~BufferView() {
+}
+
+void BufferView::Initialize(v8::Isolate* isolate,
+ v8::Handle<v8::ArrayBuffer> array) {
+ private_ = BufferView::Private::From(isolate, array);
+ bytes_ = private_->buffer();
+ num_bytes_ = private_->length();
+}
+
+} // namespace gin
diff --git a/gin/array_buffer.h b/gin/array_buffer.h
new file mode 100644
index 0000000..b48a687
--- /dev/null
+++ b/gin/array_buffer.h
@@ -0,0 +1,45 @@
+// 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_ARRAY_BUFFER_H_
+#define GIN_ARRAY_BUFFER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h" // For scoped_refptr only!
+#include "v8/include/v8.h"
+
+namespace gin {
+
+class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+ public:
+ virtual void* Allocate(size_t length) OVERRIDE;
+ virtual void* AllocateUninitialized(size_t length) OVERRIDE;
+ virtual void Free(void* data, size_t length) OVERRIDE;
+
+ static ArrayBufferAllocator* SharedInstance();
+};
+
+class BufferView {
+ public:
+ BufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBufferView> view);
+ BufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer);
+ ~BufferView();
+
+ void* bytes() const { return bytes_; }
+ size_t num_bytes() const { return num_bytes_; }
+
+ private:
+ class Private;
+
+ void Initialize(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer);
+
+ scoped_refptr<Private> private_;
+ void* bytes_;
+ size_t num_bytes_;
+};
+
+} // namespace gin
+
+#endif // GIN_ARRAY_BUFFER_H_
diff --git a/gin/converter.cc b/gin/converter.cc
new file mode 100644
index 0000000..6b30985
--- /dev/null
+++ b/gin/converter.cc
@@ -0,0 +1,102 @@
+// 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/converter.h"
+
+#include "v8/include/v8.h"
+
+using v8::Boolean;
+using v8::Function;
+using v8::Handle;
+using v8::Integer;
+using v8::Isolate;
+using v8::Number;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+namespace gin {
+
+Handle<Value> Converter<bool>::ToV8(Isolate* isolate, bool val) {
+ return Boolean::New(val).As<Value>();
+}
+
+bool Converter<bool>::FromV8(Handle<Value> val, bool* out) {
+ *out = val->BooleanValue();
+ return true;
+}
+
+Handle<Value> Converter<int32_t>::ToV8(Isolate* isolate, int32_t val) {
+ return Integer::New(val, isolate).As<Value>();
+}
+
+bool Converter<int32_t>::FromV8(Handle<Value> val, int32_t* out) {
+ if (!val->IsInt32())
+ return false;
+ *out = val->Int32Value();
+ return true;
+}
+
+Handle<Value> Converter<uint32_t>::ToV8(Isolate* isolate, uint32_t val) {
+ return Integer::NewFromUnsigned(val, isolate).As<Value>();
+}
+
+bool Converter<uint32_t>::FromV8(Handle<Value> val, uint32_t* out) {
+ if (!val->IsUint32())
+ return false;
+ *out = val->Uint32Value();
+ return true;
+}
+
+Handle<Value> Converter<double>::ToV8(Isolate* isolate, double val) {
+ return Number::New(isolate, val).As<Value>();
+}
+
+bool Converter<double>::FromV8(Handle<Value> val, double* out) {
+ if (!val->IsNumber())
+ return false;
+ *out = val->NumberValue();
+ return true;
+}
+
+Handle<Value> Converter<std::string>::ToV8(Isolate* isolate,
+ const std::string& val) {
+ return String::NewFromUtf8(isolate,
+ val.data(),
+ String::kNormalString,
+ val.length());
+}
+
+bool Converter<std::string>::FromV8(Handle<Value> val,
+ std::string* out) {
+ if (!val->IsString())
+ return false;
+ Handle<String> str = Handle<String>::Cast(val);
+ int length = str->Utf8Length();
+ out->resize(length);
+ str->WriteUtf8(&(*out)[0], length, NULL, String::NO_NULL_TERMINATION);
+ return true;
+}
+
+bool Converter<Handle<Function> >::FromV8(Handle<Value> val,
+ Handle<Function>* out) {
+ if (!val->IsFunction())
+ return false;
+ *out = Handle<Function>::Cast(val);
+ return true;
+}
+
+Handle<Value> Converter<Handle<Object> >::ToV8(Handle<Object> val) {
+ return val.As<Value>();
+}
+
+bool Converter<Handle<Object> >::FromV8(Handle<Value> val,
+ Handle<Object>* out) {
+ if (!val->IsObject())
+ return false;
+ *out = Handle<Object>::Cast(val);
+ return true;
+}
+
+} // namespace gin
diff --git a/gin/converter.h b/gin/converter.h
new file mode 100644
index 0000000..eb84be2
--- /dev/null
+++ b/gin/converter.h
@@ -0,0 +1,121 @@
+// 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_CONVERTER_H_
+#define GIN_CONVERTER_H_
+
+#include <string>
+#include <vector>
+
+#include "v8/include/v8.h"
+
+namespace gin {
+
+template<typename T>
+struct Converter {};
+
+template<>
+struct Converter<bool> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ bool val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ bool* out);
+};
+
+template<>
+struct Converter<int32_t> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ int32_t val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ int32_t* out);
+};
+
+template<>
+struct Converter<uint32_t> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ uint32_t val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ uint32_t* out);
+};
+
+template<>
+struct Converter<double> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ double val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ double* out);
+};
+
+template<>
+struct Converter<std::string> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ const std::string& val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ std::string* out);
+};
+
+template<>
+struct Converter<v8::Handle<v8::Function> > {
+ static bool FromV8(v8::Handle<v8::Value> val,
+ v8::Handle<v8::Function>* out);
+};
+
+template<>
+struct Converter<v8::Handle<v8::Object> > {
+ static v8::Handle<v8::Value> ToV8(v8::Handle<v8::Object> val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ v8::Handle<v8::Object>* out);
+};
+
+template<typename T>
+struct Converter<std::vector<T> > {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ const std::vector<T>& val) {
+ v8::Handle<v8::Array> result(v8::Array::New(static_cast<int>(val.size())));
+ for (size_t i = 0; i < val.size(); ++i) {
+ result->Set(static_cast<int>(i), Converter<T>::ToV8(isolate, val[i]));
+ }
+ return result;
+ }
+
+ static bool FromV8(v8::Handle<v8::Value> val,
+ std::vector<T>* out) {
+ if (!val->IsArray())
+ return false;
+
+ std::vector<T> result;
+ v8::Handle<v8::Array> array(v8::Handle<v8::Array>::Cast(val));
+ uint32_t length = array->Length();
+ for (uint32_t i = 0; i < length; ++i) {
+ T item;
+ if (!Converter<T>::FromV8(array->Get(i), &item))
+ return false;
+ result.push_back(item);
+ }
+
+ out->swap(result);
+ return true;
+ }
+};
+
+// Convenience functions that deduce T.
+template<typename T>
+v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate,
+ T input) {
+ return Converter<T>::ToV8(isolate, input);
+}
+
+inline v8::Handle<v8::String> StringToV8(
+ v8::Isolate* isolate, std::string input) {
+ return ConvertToV8(isolate, input).As<v8::String>();
+}
+
+template<typename T>
+bool ConvertFromV8(v8::Handle<v8::Value> input, T* result) {
+ return Converter<T>::FromV8(input, result);
+}
+
+} // namespace gin
+
+#endif // GIN_CONVERTER_H_
diff --git a/gin/converter_unittest.cc b/gin/converter_unittest.cc
new file mode 100644
index 0000000..b98a6da
--- /dev/null
+++ b/gin/converter_unittest.cc
@@ -0,0 +1,128 @@
+// 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/converter.h"
+
+#include <limits.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "gin/test/v8_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+using v8::Array;
+using v8::Boolean;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Null;
+using v8::Number;
+using v8::Object;
+using v8::String;
+using v8::Undefined;
+using v8::Value;
+
+namespace gin {
+
+typedef V8Test ConverterTest;
+
+TEST_F(ConverterTest, Bool) {
+ HandleScope handle_scope(isolate_);
+
+ EXPECT_TRUE(Converter<bool>::ToV8(isolate_, true)->StrictEquals(
+ Boolean::New(true)));
+ EXPECT_TRUE(Converter<bool>::ToV8(isolate_, false)->StrictEquals(
+ Boolean::New(false)));
+
+ struct {
+ Handle<Value> input;
+ bool expected;
+ } test_data[] = {
+ { Boolean::New(false).As<Value>(), false },
+ { Boolean::New(true).As<Value>(), true },
+ { Number::New(0).As<Value>(), false },
+ { Number::New(1).As<Value>(), true },
+ { Number::New(-1).As<Value>(), true },
+ { Number::New(0.1).As<Value>(), true },
+ { String::New("").As<Value>(), false },
+ { String::New("foo").As<Value>(), true },
+ { Object::New().As<Value>(), true },
+ { Null().As<Value>(), false },
+ { Undefined().As<Value>(), false },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
+ bool result = false;
+ EXPECT_TRUE(Converter<bool>::FromV8(test_data[i].input, &result));
+ EXPECT_EQ(test_data[i].expected, result);
+
+ result = true;
+ EXPECT_TRUE(Converter<bool>::FromV8(test_data[i].input, &result));
+ EXPECT_EQ(test_data[i].expected, result);
+ }
+}
+
+TEST_F(ConverterTest, Int32) {
+ HandleScope handle_scope(isolate_);
+
+ 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(isolate_,
+ test_data_to[i])->StrictEquals(Integer::New(test_data_to[i])));
+ }
+
+ struct {
+ v8::Handle<v8::Value> input;
+ bool expect_sucess;
+ int expected_result;
+ } test_data_from[] = {
+ { Boolean::New(false).As<Value>(), false, 0 },
+ { Boolean::New(true).As<Value>(), false, 0 },
+ { Integer::New(-1).As<Value>(), true, -1 },
+ { Integer::New(0).As<Value>(), true, 0 },
+ { Integer::New(1).As<Value>(), true, 1 },
+ { Number::New(-1).As<Value>(), true, -1 },
+ { Number::New(1.1).As<Value>(), false, 0 },
+ { String::New("42").As<Value>(), false, 0 },
+ { String::New("foo").As<Value>(), false, 0 },
+ { Object::New().As<Value>(), false, 0 },
+ { Array::New().As<Value>(), false, 0 },
+ { v8::Null().As<Value>(), false, 0 },
+ { v8::Undefined().As<Value>(), false, 0 },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data_from); ++i) {
+ int32_t result = std::numeric_limits<int32_t>::min();
+ bool success = Converter<int32_t>::FromV8(test_data_from[i].input, &result);
+ EXPECT_EQ(test_data_from[i].expect_sucess, success) << i;
+ if (success)
+ EXPECT_EQ(test_data_from[i].expected_result, result) << i;
+ }
+}
+
+TEST_F(ConverterTest, Vector) {
+ HandleScope handle_scope(isolate_);
+
+ std::vector<int> expected;
+ expected.push_back(-1);
+ expected.push_back(0);
+ expected.push_back(1);
+
+ Handle<Array> js_array = Handle<Array>::Cast(
+ Converter<std::vector<int> >::ToV8(isolate_, expected));
+ ASSERT_FALSE(js_array.IsEmpty());
+ EXPECT_EQ(3u, js_array->Length());
+ for (size_t i = 0; i < expected.size(); ++i) {
+ EXPECT_TRUE(Integer::New(expected[i])->StrictEquals(
+ js_array->Get(static_cast<int>(i))));
+ }
+
+ std::vector<int> actual;
+ EXPECT_TRUE(Converter<std::vector<int> >::FromV8(js_array, &actual));
+ EXPECT_EQ(expected, actual);
+}
+
+} // namespace gin
diff --git a/gin/gin.gyp b/gin/gin.gyp
new file mode 100644
index 0000000..ca133dd
--- /dev/null
+++ b/gin/gin.gyp
@@ -0,0 +1,54 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'gin',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..'
+ ],
+ 'dependencies': [
+ '../v8/tools/gyp/v8.gyp:v8',
+ ],
+ 'export_dependent_settings': [
+ '../v8/tools/gyp/v8.gyp:v8',
+ ],
+ 'sources': [
+ 'array_buffer.cc',
+ 'array_buffer.h',
+ 'converter.cc',
+ 'converter.h',
+ 'initialize.cc',
+ 'initialize.h',
+ 'per_isolate_data.cc',
+ 'per_isolate_data.h',
+ 'runner.cc',
+ 'runner.h',
+ 'wrapper_info.cc',
+ 'wrapper_info.h',
+ ],
+ },
+ {
+ 'target_name': 'gin_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/base.gyp:run_all_unittests',
+ '../testing/gtest.gyp:gtest',
+ 'gin',
+ ],
+ 'sources': [
+ 'test/v8_test.cc',
+ 'test/run_all_unittests.cc',
+ 'converter_unittest.cc',
+ 'runner_unittest.cc',
+ ],
+ },
+ ],
+}
diff --git a/gin/initialize.cc b/gin/initialize.cc
new file mode 100644
index 0000000..450ff2a
--- /dev/null
+++ b/gin/initialize.cc
@@ -0,0 +1,38 @@
+// 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/initialize.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gin/array_buffer.h"
+#include "gin/per_isolate_data.h"
+
+namespace gin {
+
+namespace {
+
+bool GenerateEntropy(unsigned char* buffer, size_t amount) {
+ // TODO(abarth): Gin needs a source of entropy.
+ return false;
+}
+
+const char kFlags[] = "--use_strict --harmony";
+
+}
+
+void Initialize() {
+ v8::V8::SetArrayBufferAllocator(ArrayBufferAllocator::SharedInstance());
+ v8::V8::InitializeICU();
+ v8::V8::SetFlagsFromString(kFlags, strlen(kFlags));
+ v8::V8::SetEntropySource(&GenerateEntropy);
+ v8::V8::Initialize();
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ new PerIsolateData(isolate);
+}
+
+} // namespace gin
diff --git a/gin/initialize.h b/gin/initialize.h
new file mode 100644
index 0000000..4ebcf8d
--- /dev/null
+++ b/gin/initialize.h
@@ -0,0 +1,14 @@
+// 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_INITIALIZE_H_
+#define GIN_INITIALIZE_H_
+
+namespace gin {
+
+void Initialize();
+
+} // namespace gin
+
+#endif // GIN_INITIALIZE_H_
diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc
new file mode 100644
index 0000000..1320904
--- /dev/null
+++ b/gin/per_isolate_data.cc
@@ -0,0 +1,33 @@
+// 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/per_isolate_data.h"
+
+using v8::Eternal;
+using v8::Handle;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+
+namespace gin {
+
+PerIsolateData::PerIsolateData(Isolate* isolate)
+ : isolate_(isolate) {
+ isolate_->SetData(this);
+}
+
+PerIsolateData::~PerIsolateData() {
+}
+
+PerIsolateData* PerIsolateData::From(Isolate* isolate) {
+ return static_cast<PerIsolateData*>(isolate->GetData());
+}
+
+void PerIsolateData::RegisterObjectTemplate(
+ WrapperInfo* info, Local<ObjectTemplate> object_template) {
+ object_templates_[info] = Eternal<ObjectTemplate>(isolate_, object_template);
+}
+
+} // namespace gin
diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h
new file mode 100644
index 0000000..72467b8
--- /dev/null
+++ b/gin/per_isolate_data.h
@@ -0,0 +1,38 @@
+// 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_PER_ISOLATE_DATA_H_
+#define GIN_PER_ISOLATE_DATA_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "gin/wrapper_info.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+class PerIsolateData {
+ public:
+ explicit PerIsolateData(v8::Isolate* isolate);
+ ~PerIsolateData();
+
+ static PerIsolateData* From(v8::Isolate* isolate);
+
+ void RegisterObjectTemplate(WrapperInfo* info,
+ v8::Local<v8::ObjectTemplate> object_template);
+
+ private:
+ typedef std::map<
+ WrapperInfo*, v8::Eternal<v8::ObjectTemplate> > ObjectTemplateMap;
+
+ v8::Isolate* isolate_;
+ ObjectTemplateMap object_templates_;
+
+ DISALLOW_COPY_AND_ASSIGN(PerIsolateData);
+};
+
+} // namespace gin
+
+#endif // GIN_PER_ISOLATE_DATA_H_
diff --git a/gin/runner.cc b/gin/runner.cc
new file mode 100644
index 0000000..cf98399
--- /dev/null
+++ b/gin/runner.cc
@@ -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.
+
+#include "gin/runner.h"
+
+#include "gin/converter.h"
+
+using v8::Context;
+using v8::Function;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::Script;
+using v8::String;
+using v8::Value;
+
+namespace gin {
+
+RunnerDelegate::~RunnerDelegate() {
+}
+
+Runner::Runner(RunnerDelegate* delegate, Isolate* isolate)
+ : delegate_(delegate),
+ isolate_(isolate) {
+ HandleScope handle_scope(isolate_);
+ context_.Reset(isolate_, Context::New(isolate_));
+}
+
+Runner::~Runner() {
+ // TODO(abarth): Figure out how to set kResetInDestructor to true.
+ context_.Reset();
+}
+
+void Runner::Run(Handle<Script> script) {
+ script->Run();
+ Handle<Function> main = GetMain();
+ if (main.IsEmpty())
+ return;
+ Handle<Value> argv[] = { delegate_->CreateRootObject(this) };
+ main->Call(global(), 1, argv);
+}
+
+v8::Handle<v8::Function> Runner::GetMain() {
+ Handle<Value> property = global()->Get(StringToV8(isolate_, "main"));
+ if (property.IsEmpty())
+ return v8::Handle<v8::Function>();
+ Handle<Function> main;
+ if (!ConvertFromV8(property, &main))
+ return v8::Handle<v8::Function>();
+ return main;
+}
+
+Runner::Scope::Scope(Runner* runner)
+ : handle_scope_(runner->isolate_),
+ scope_(Local<Context>::New(runner->isolate_, runner->context_)) {
+}
+
+Runner::Scope::~Scope() {
+}
+
+} // namespace gin
diff --git a/gin/runner.h b/gin/runner.h
new file mode 100644
index 0000000..c74de16
--- /dev/null
+++ b/gin/runner.h
@@ -0,0 +1,67 @@
+// 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_RUNNER_H_
+#define GIN_RUNNER_H_
+
+#include "base/basictypes.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+class Runner;
+
+class RunnerDelegate {
+ public:
+ // Returns the object that is passed to the script's |main| function.
+ virtual v8::Handle<v8::Object> CreateRootObject(Runner* runner) = 0;
+
+ protected:
+ virtual ~RunnerDelegate();
+};
+
+class Runner {
+ public:
+ Runner(RunnerDelegate* delegate, v8::Isolate* isolate);
+ ~Runner();
+
+ void Run(v8::Handle<v8::Script> script);
+
+ v8::Isolate* isolate() const { return isolate_; }
+
+ v8::Handle<v8::Context> context() const {
+ return v8::Local<v8::Context>::New(isolate_, context_);
+ }
+
+ v8::Handle<v8::Object> global() const {
+ return context()->Global();
+ }
+
+ class Scope {
+ public:
+ explicit Scope(Runner* runner);
+ ~Scope();
+
+ private:
+ v8::HandleScope handle_scope_;
+ v8::Context::Scope scope_;
+
+ DISALLOW_COPY_AND_ASSIGN(Scope);
+ };
+
+ private:
+ friend class Scope;
+
+ v8::Handle<v8::Function> GetMain();
+
+ RunnerDelegate* delegate_;
+ v8::Isolate* isolate_;
+ v8::Persistent<v8::Context> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(Runner);
+};
+
+} // namespace gin
+
+#endif // GIN_RUNNER_H_
diff --git a/gin/runner_unittest.cc b/gin/runner_unittest.cc
new file mode 100644
index 0000000..4b3c0fc
--- /dev/null
+++ b/gin/runner_unittest.cc
@@ -0,0 +1,55 @@
+// 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/runner.h"
+
+#include "base/compiler_specific.h"
+#include "gin/converter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using v8::Handle;
+using v8::Isolate;
+using v8::Object;
+using v8::Script;
+using v8::String;
+
+namespace gin {
+namespace {
+
+class TestRunnerDelegate : public RunnerDelegate {
+ public:
+ virtual Handle<Object> CreateRootObject(Runner* runner) OVERRIDE {
+ Isolate* isolate = runner->isolate();
+ Handle<Object> root = Object::New();
+ root->Set(StringToV8(isolate, "foo"), StringToV8(isolate, "bar"));
+ return root;
+ }
+ virtual ~TestRunnerDelegate() {}
+};
+
+}
+
+TEST(RunnerTest, Run) {
+ std::string source =
+ "function main(root) {\n"
+ " if (root.foo)\n"
+ " this.result = 'PASS';\n"
+ " else\n"
+ " this.result = 'FAIL';\n"
+ "}\n";
+
+ TestRunnerDelegate delegate;
+ Isolate* isolate = Isolate::GetCurrent();
+ Runner runner(&delegate, isolate);
+ Runner::Scope scope(&runner);
+ runner.Run(Script::New(StringToV8(isolate, source)));
+
+ std::string result;
+ EXPECT_TRUE(Converter<std::string>::FromV8(
+ runner.global()->Get(StringToV8(isolate, "result")),
+ &result));
+ EXPECT_EQ("PASS", result);
+}
+
+} // namespace gin
diff --git a/gin/test/run_all_unittests.cc b/gin/test/run_all_unittests.cc
new file mode 100644
index 0000000..c8644ed
--- /dev/null
+++ b/gin/test/run_all_unittests.cc
@@ -0,0 +1,20 @@
+// 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 "base/basictypes.h"
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "gin/initialize.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+
+ gin::Initialize();
+
+ return base::LaunchUnitTests(
+ argc, argv, base::Bind(&base::TestSuite::Run,
+ base::Unretained(&test_suite)));
+}
diff --git a/gin/test/v8_test.cc b/gin/test/v8_test.cc
new file mode 100644
index 0000000..b2c1d5d
--- /dev/null
+++ b/gin/test/v8_test.cc
@@ -0,0 +1,33 @@
+// 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/test/v8_test.h"
+
+using v8::Context;
+using v8::Local;
+using v8::HandleScope;
+using v8::Isolate;
+
+namespace gin {
+
+V8Test::V8Test() {
+}
+
+V8Test::~V8Test() {
+}
+
+void V8Test::SetUp() {
+ isolate_ = Isolate::GetCurrent();
+ HandleScope handle_scope(isolate_);
+ context_.Reset(isolate_, Context::New(isolate_));
+ Local<Context>::New(isolate_, context_)->Enter();
+}
+
+void V8Test::TearDown() {
+ HandleScope handle_scope(isolate_);
+ Local<Context>::New(isolate_, context_)->Exit();
+ context_.Reset();
+}
+
+} // namespace gin
diff --git a/gin/test/v8_test.h b/gin/test/v8_test.h
new file mode 100644
index 0000000..2b46f24
--- /dev/null
+++ b/gin/test/v8_test.h
@@ -0,0 +1,30 @@
+// 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_TEST_V8_TEST_H_
+#define GIN_TEST_V8_TEST_H_
+
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+namespace gin {
+
+// A base class for tests that use v8.
+class V8Test : public testing::Test {
+ public:
+ V8Test();
+ virtual ~V8Test();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ v8::Isolate* isolate_;
+ v8::Persistent<v8::Context> context_;
+};
+
+} // namespace gin
+
+#endif // GIN_TEST_V8_TEST_H_
diff --git a/gin/wrapper_info.cc b/gin/wrapper_info.cc
new file mode 100644
index 0000000..d14156d
--- /dev/null
+++ b/gin/wrapper_info.cc
@@ -0,0 +1,16 @@
+// 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/wrapper_info.h"
+
+namespace gin {
+
+WrapperInfo* WrapperInfo::From(v8::Handle<v8::Object> object) {
+ if (object->InternalFieldCount() != kNumberOfInternalFields)
+ return NULL;
+ return static_cast<WrapperInfo*>(
+ object->GetAlignedPointerFromInternalField(kWrapperInfoIndex));
+}
+
+} // namespace gin
diff --git a/gin/wrapper_info.h b/gin/wrapper_info.h
new file mode 100644
index 0000000..16eef25
--- /dev/null
+++ b/gin/wrapper_info.h
@@ -0,0 +1,25 @@
+// 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_WRAPPER_INFO_H_
+#define GIN_WRAPPER_INFO_H_
+
+#include "v8/include/v8.h"
+
+namespace gin {
+
+enum InternalFields {
+ kWrapperInfoIndex,
+ kEncodedValueIndex,
+ kNumberOfInternalFields,
+};
+
+struct WrapperInfo {
+ static WrapperInfo* From(v8::Handle<v8::Object> object);
+ // Currently we just use the address of this struct for identity.
+};
+
+} // namespace gin
+
+#endif // GIN_WRAPPER_INFO_H_