summaryrefslogtreecommitdiffstats
path: root/gin
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-27 02:10:15 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-27 02:10:15 +0000
commit60531d54b668c625ea5e2e7d4285ae8ac7388691 (patch)
treea4115e697100a456647bd76d93d58f039e04eff8 /gin
parent3af5a0aed53fe0a189e4e39d6885ea791d0473fa (diff)
downloadchromium_src-60531d54b668c625ea5e2e7d4285ae8ac7388691.zip
chromium_src-60531d54b668c625ea5e2e7d4285ae8ac7388691.tar.gz
chromium_src-60531d54b668c625ea5e2e7d4285ae8ac7388691.tar.bz2
[Gin] Add documentation to explain how Gin works
This code is likely to evolve over time, but we've reached a stage where the basic structure is mostly in place. This CL documents this structure so that future developers will understand what we have in mind now. R=aa@chromium.org BUG=none Review URL: https://codereview.chromium.org/88913006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237485 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r--gin/arguments.h3
-rw-r--r--gin/context_holder.h3
-rw-r--r--gin/dictionary.h12
-rw-r--r--gin/modules/console.h2
-rw-r--r--gin/modules/file_module_provider.h9
-rw-r--r--gin/modules/module_runner_delegate.h8
-rw-r--r--gin/per_context_data.h10
-rw-r--r--gin/per_isolate_data.h11
-rw-r--r--gin/public/isolate_holder.h16
-rw-r--r--gin/runner.h9
-rw-r--r--gin/test/file_runner.h5
-rw-r--r--gin/test/gtest.h3
-rw-r--r--gin/test/v8_test.h3
-rw-r--r--gin/try_catch.h7
-rw-r--r--gin/wrappable.h37
15 files changed, 127 insertions, 11 deletions
diff --git a/gin/arguments.h b/gin/arguments.h
index 8a372ea..fe4c6aa 100644
--- a/gin/arguments.h
+++ b/gin/arguments.h
@@ -10,6 +10,9 @@
namespace gin {
+// Arguments is a wrapper around v8::FunctionCallbackInfo that integrates
+// with Converter to make it easier to marshall arguments and return values
+// between V8 and C++.
class Arguments {
public:
explicit Arguments(const v8::FunctionCallbackInfo<v8::Value>& info);
diff --git a/gin/context_holder.h b/gin/context_holder.h
index d43e193..adb9d80 100644
--- a/gin/context_holder.h
+++ b/gin/context_holder.h
@@ -15,6 +15,9 @@ namespace gin {
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.
class ContextHolder {
public:
explicit ContextHolder(v8::Isolate* isolate);
diff --git a/gin/dictionary.h b/gin/dictionary.h
index f011779..a6b450b 100644
--- a/gin/dictionary.h
+++ b/gin/dictionary.h
@@ -9,6 +9,18 @@
namespace gin {
+// Dictionary is useful when writing bindings for a function that either
+// receives an arbitrary JavaScript object as an argument or returns an
+// arbitrary JavaScript object as a result. For example, Dictionary is useful
+// when you might use the |dictionary| type in WebIDL:
+//
+// http://heycam.github.io/webidl/#idl-dictionaries
+//
+// WARNING: You cannot retain a Dictionary object in the heap. The underlying
+// storage for Dictionary is tied to the closest enclosing
+// v8::HandleScope. Generally speaking, you should store a Dictionary
+// on the stack.
+//
class Dictionary {
public:
explicit Dictionary(v8::Isolate* isolate);
diff --git a/gin/modules/console.h b/gin/modules/console.h
index 139a6c9..259fdaa7 100644
--- a/gin/modules/console.h
+++ b/gin/modules/console.h
@@ -9,6 +9,8 @@
namespace gin {
+// The Console module provides a basic API for printing to stdout. Over time,
+// we'd like to evolve the API to match window.console in browsers.
class Console {
public:
static const char kModuleName[];
diff --git a/gin/modules/file_module_provider.h b/gin/modules/file_module_provider.h
index e82d8e3..89e83b3 100644
--- a/gin/modules/file_module_provider.h
+++ b/gin/modules/file_module_provider.h
@@ -14,16 +14,25 @@
namespace gin {
+// FileModuleProvider knows how to load AMD modules off disk. It searches for
+// modules in the directories indiciated by |search_paths|. Although we still
+// read from the file system on the main thread, we'll eventually want to move
+// the reads to a background thread.
class FileModuleProvider {
public:
explicit FileModuleProvider(
const std::vector<base::FilePath>& search_paths);
~FileModuleProvider();
+ // Searches for modules with |ids| in the file system. If found, the modules
+ // will be executed asynchronously by |runner|.
void AttempToLoadModules(Runner* runner, const std::set<std::string>& ids);
private:
std::vector<base::FilePath> search_paths_;
+
+ // We'll only search for a given module once. We remember the set of modules
+ // we've already looked for in |attempted_ids_|.
std::set<std::string> attempted_ids_;
DISALLOW_COPY_AND_ASSIGN(FileModuleProvider);
diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h
index efc9761..d5523b8 100644
--- a/gin/modules/module_runner_delegate.h
+++ b/gin/modules/module_runner_delegate.h
@@ -16,12 +16,20 @@ namespace gin {
typedef v8::Local<v8::ObjectTemplate> (*ModuleTemplateGetter)(
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 ModuleRunnerDelegate : public RunnerDelegate {
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);
private:
diff --git a/gin/per_context_data.h b/gin/per_context_data.h
index b89c5a6..ea8b169 100644
--- a/gin/per_context_data.h
+++ b/gin/per_context_data.h
@@ -14,17 +14,23 @@ namespace gin {
class Runner;
+// Embedders can store additional per-context data by subclassing
+// ContextSupplement.
class 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 PerContextData {
public:
explicit PerContextData(v8::Handle<v8::Context> context);
@@ -34,8 +40,10 @@ class PerContextData {
static PerContextData* From(v8::Handle<v8::Context>);
void Detach(v8::Handle<v8::Context> context);
- void set_runner(Runner* runner) { runner_ = runner; }
+ // 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);
diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h
index 7ed9da7..4801125 100644
--- a/gin/per_isolate_data.h
+++ b/gin/per_isolate_data.h
@@ -13,6 +13,8 @@
namespace gin {
+// 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 PerIsolateData {
public:
explicit PerIsolateData(v8::Isolate* isolate);
@@ -20,11 +22,18 @@ class PerIsolateData {
static PerIsolateData* From(v8::Isolate* isolate);
+ // Each isolate is associated with a collection of v8::ObjectTemplates and
+ // v8::FunctionTemplates. Typically these template objects are created
+ // lazily.
void SetObjectTemplate(WrapperInfo* info,
v8::Local<v8::ObjectTemplate> object_template);
void SetFunctionTemplate(WrapperInfo* info,
v8::Local<v8::FunctionTemplate> function_template);
+ // These are low-level functions for retrieving object or function templates
+ // stored in this object. Because these templates are often created lazily,
+ // most clients should call higher-level functions that know how to populate
+ // these templates if they haven't already been created.
v8::Local<v8::ObjectTemplate> GetObjectTemplate(WrapperInfo* info);
v8::Local<v8::FunctionTemplate> GetFunctionTemplate(WrapperInfo* info);
@@ -34,6 +43,8 @@ class PerIsolateData {
typedef std::map<
WrapperInfo*, v8::Eternal<v8::FunctionTemplate> > FunctionTemplateMap;
+ // PerIsolateData doesn't actually own |isolate_|. Instead, the isolate is
+ // owned by the IsolateHolder, which also owns the PerIsolateData.
v8::Isolate* isolate_;
ObjectTemplateMap object_templates_;
FunctionTemplateMap function_templates_;
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index 15755a4..809d329 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -16,14 +16,18 @@ namespace gin {
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
+//
+// 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.
+//
+// It is not possible to mix the two.
class IsolateHolder {
public:
- // 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.
- //
- // It is not possible to mix the two.
IsolateHolder();
explicit IsolateHolder(v8::Isolate* isolate);
diff --git a/gin/runner.h b/gin/runner.h
index 21e656f..cbebc76 100644
--- a/gin/runner.h
+++ b/gin/runner.h
@@ -15,6 +15,9 @@ 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 RunnerDelegate {
public:
RunnerDelegate();
@@ -28,11 +31,15 @@ class RunnerDelegate {
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 Runner : public ContextHolder {
public:
Runner(RunnerDelegate* delegate, v8::Isolate* isolate);
~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);
@@ -45,6 +52,8 @@ class Runner : public ContextHolder {
return context()->Global();
}
+ // Useful for running script in this context asynchronously. Rather than
+ // holding a raw pointer to the runner, consider holding a WeakPtr.
base::WeakPtr<Runner> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
diff --git a/gin/test/file_runner.h b/gin/test/file_runner.h
index c4164f5..57d4017 100644
--- a/gin/test/file_runner.h
+++ b/gin/test/file_runner.h
@@ -12,6 +12,11 @@
namespace gin {
+// FileRunnerDelegate is a simple RunnerDelegate that's useful for running
+// tests. The FileRunnerDelegate provides built-in modules for "console" and
+// "gtest" that are useful when writing unit tests.
+//
+// TODO(abarth): Rename FileRunnerDelegate to TestRunnerDelegate.
class FileRunnerDelegate : public ModuleRunnerDelegate {
public:
FileRunnerDelegate();
diff --git a/gin/test/gtest.h b/gin/test/gtest.h
index ee19b71..2bd6944 100644
--- a/gin/test/gtest.h
+++ b/gin/test/gtest.h
@@ -9,6 +9,9 @@
namespace gin {
+// This module provides bindings to gtest. Most tests should use an idiomatic
+// JavaScript testing API, but this module is available for tests that need a
+// low-level integration with gtest.
class GTest {
public:
static const char kModuleName[];
diff --git a/gin/test/v8_test.h b/gin/test/v8_test.h
index 6ad52d6..e62aa57 100644
--- a/gin/test/v8_test.h
+++ b/gin/test/v8_test.h
@@ -15,7 +15,8 @@ namespace gin {
class IsolateHolder;
-// A base class for tests that use v8.
+// V8Test is a simple harness for testing interactions with V8. V8Test doesn't
+// have any dependencies on Gin's module system.
class V8Test : public testing::Test {
public:
V8Test();
diff --git a/gin/try_catch.h b/gin/try_catch.h
index 43f68ac..390fb22 100644
--- a/gin/try_catch.h
+++ b/gin/try_catch.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef GIN_EXCEPTION_H_
-#define GIN_EXCEPTION_H_
+#ifndef GIN_TRY_CATCH_H_
+#define GIN_TRY_CATCH_H_
#include <string>
@@ -12,6 +12,7 @@
namespace gin {
+// TryCatch is a convenient wrapper around v8::TryCatch.
class TryCatch {
public:
TryCatch();
@@ -28,4 +29,4 @@ class TryCatch {
} // namespace gin
-#endif // GIN_EXCEPTION_H_
+#endif // GIN_TRY_CATCH_H_
diff --git a/gin/wrappable.h b/gin/wrappable.h
index 79b7144..f8d0b95 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -11,10 +11,44 @@
namespace gin {
+// Wrappable is an abstract base class for C++ objects that have cooresponding
+// v8 wrapper objects. Wrappable are RefCounted, which means they can be
+// retained either by V8's garbage collector or by a scoped_refptr.
+//
+// WARNING: If you retain a Wrappable object with a scoped_refptr, it's possible
+// that the v8 wrapper can "fall off" if the wrapper object is not
+// referenced elsewhere in the V8 heap. Although Wrappable opens a
+// handle to the wrapper object, we make that handle as weak, which
+// means V8 is free to reclaim the wrapper. (We can't make the handle
+// strong without risking introducing a memory leak if an object that
+// holds a scoped_refptr is reachable from the wrapper.)
+//
class Wrappable : public base::RefCounted<Wrappable> {
public:
+ // Subclasses must return the WrapperInfo object associated with the
+ // v8::ObjectTemplate for their subclass. When creating a v8 wrapper for
+ // this object, we'll look up the appropriate v8::ObjectTemplate in the
+ // PerIsolateData using this WrapperInfo pointer.
virtual WrapperInfo* GetWrapperInfo() = 0;
+ // Subclasses much also contain a static member variable named |kWrapperInfo|
+ // of type WrapperInfo:
+ //
+ // static WrapperInfo kWrapperInfo;
+ //
+ // If |obj| is a concrete instance of the subclass, then obj->GetWrapperInfo()
+ // must return &kWrapperInfo.
+ //
+ // We use both the dynamic |GetWrapperInfo| function and the static
+ // |kWrapperInfo| member variable during wrapping and the unwrapping. During
+ // wrapping, we use GetWrapperInfo() to make sure we use the correct
+ // v8::ObjectTemplate for the object regardless of the declared C++ type.
+ // During unwrapping, we use the static member variable to prevent type errors
+ // during the downcast from Wrappable to the subclass.
+
+ // Retrieve (or create) the v8 wrapper object cooresponding to this object.
+ // To customize the wrapper created for a subclass, override GetWrapperInfo()
+ // instead of overriding this function.
v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate);
protected:
@@ -52,6 +86,9 @@ struct WrappableConverter {
if (!Converter<Wrappable*>::FromV8(val, &wrappable)
|| wrappable->GetWrapperInfo() != &T::kWrapperInfo)
return false;
+ // Currently we require that you unwrap to the exact runtime type of the
+ // wrapped object.
+ // TODO(abarth): Support unwrapping to a base class.
*out = static_cast<T*>(wrappable);
return true;
}