diff options
author | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-27 02:10:15 +0000 |
---|---|---|
committer | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-27 02:10:15 +0000 |
commit | 60531d54b668c625ea5e2e7d4285ae8ac7388691 (patch) | |
tree | a4115e697100a456647bd76d93d58f039e04eff8 /gin | |
parent | 3af5a0aed53fe0a189e4e39d6885ea791d0473fa (diff) | |
download | chromium_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.h | 3 | ||||
-rw-r--r-- | gin/context_holder.h | 3 | ||||
-rw-r--r-- | gin/dictionary.h | 12 | ||||
-rw-r--r-- | gin/modules/console.h | 2 | ||||
-rw-r--r-- | gin/modules/file_module_provider.h | 9 | ||||
-rw-r--r-- | gin/modules/module_runner_delegate.h | 8 | ||||
-rw-r--r-- | gin/per_context_data.h | 10 | ||||
-rw-r--r-- | gin/per_isolate_data.h | 11 | ||||
-rw-r--r-- | gin/public/isolate_holder.h | 16 | ||||
-rw-r--r-- | gin/runner.h | 9 | ||||
-rw-r--r-- | gin/test/file_runner.h | 5 | ||||
-rw-r--r-- | gin/test/gtest.h | 3 | ||||
-rw-r--r-- | gin/test/v8_test.h | 3 | ||||
-rw-r--r-- | gin/try_catch.h | 7 | ||||
-rw-r--r-- | gin/wrappable.h | 37 |
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; } |