[go: nahoru, domu]

[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
diff --git a/gin/arguments.h b/gin/arguments.h
index 8a372ea..fe4c6aa3 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 d43e1933..adb9d80 100644
--- a/gin/context_holder.h
+++ b/gin/context_holder.h
@@ -15,6 +15,9 @@
 
 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..89e83b3b 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..d5523b8c 100644
--- a/gin/modules/module_runner_delegate.h
+++ b/gin/modules/module_runner_delegate.h
@@ -16,12 +16,20 @@
 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 @@
 
 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 @@
   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 7ed9da74..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 @@
 
   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 @@
   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 @@
 
 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 @@
 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 @@
   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 @@
     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..57d4017d 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 ee19b715..2bd69447 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..e62aa570e 100644
--- a/gin/test/v8_test.h
+++ b/gin/test/v8_test.h
@@ -15,7 +15,8 @@
 
 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 @@
 
 }  // namespace gin
 
-#endif  // GIN_EXCEPTION_H_
+#endif  // GIN_TRY_CATCH_H_
diff --git a/gin/wrappable.h b/gin/wrappable.h
index 79b71447..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 @@
     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;
   }