Commit 855ab43d authored by abarth@chromium.org's avatar abarth@chromium.org

Introduce gin_shell

This CL adds a simple shell program for Gin to make edit/test/debug cycle
faster. The shell excutes a list of scripts from the command line and loads any
requested AMD modules relative to the current working directory.

This CL will also let us remove the ugly code in
https://codereview.chromium.org/69843003/diff/240001/mojo/public/bindings/js/test/run_js_tests.cc
because we now know how to file modules via the file system. Eventually for
Mojo, we'll want to use a net_module_provider (instead of the
file_module_provider included in this CL) to load additional AMD modules off
the network.

BUG=317398
R=jochen@chromium.org

Review URL: https://codereview.chromium.org/74753002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235750 0039d316-1c4b-4281-b951-d872f2087c98
parent a29e465a
include_rules = [ 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", "+base",
"+v8",
] ]
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "gin/arguments.h" #include "gin/arguments.h"
#include <sstream> #include "base/strings/stringprintf.h"
#include "gin/converter.h" #include "gin/converter.h"
namespace gin { namespace gin {
...@@ -29,9 +29,8 @@ void Arguments::ThrowError() { ...@@ -29,9 +29,8 @@ void Arguments::ThrowError() {
if (insufficient_arguments_) if (insufficient_arguments_)
return ThrowTypeError("Insufficient number of arguments."); return ThrowTypeError("Insufficient number of arguments.");
std::stringstream stream; ThrowTypeError(base::StringPrintf(
stream << "Error processing argument " << next_ - 1 << "."; "Error processing argument %d.", next_ - 1));
ThrowTypeError(stream.str());
} }
void Arguments::ThrowTypeError(const std::string& message) { void Arguments::ThrowTypeError(const std::string& message) {
......
...@@ -53,26 +53,25 @@ ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() { ...@@ -53,26 +53,25 @@ ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
// a pointer to the ArrayBuffer::Private object in an internal field of the // a pointer to the ArrayBuffer::Private object in an internal field of the
// ArrayBuffer object. // ArrayBuffer object.
// //
class ArrayBuffer::Private { class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> {
public: public:
static scoped_refptr<Private> From(v8::Isolate* isolate, static scoped_refptr<Private> From(v8::Isolate* isolate,
v8::Handle<v8::ArrayBuffer> array); v8::Handle<v8::ArrayBuffer> array);
void AddRef();
void Release();
void* buffer() const { return buffer_; } void* buffer() const { return buffer_; }
size_t length() const { return length_; } size_t length() const { return length_; }
private: private:
friend class base::RefCounted<Private>;
Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array); Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array);
~Private(); ~Private();
static void WeakCallback( static void WeakCallback(
const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data); const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data);
size_t ref_count_;
v8::Persistent<v8::ArrayBuffer> array_buffer_; v8::Persistent<v8::ArrayBuffer> array_buffer_;
scoped_refptr<Private> self_reference_;
void* buffer_; void* buffer_;
size_t length_; size_t length_;
}; };
...@@ -86,20 +85,9 @@ scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From( ...@@ -86,20 +85,9 @@ scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From(
return make_scoped_refptr(new Private(isolate, array)); return make_scoped_refptr(new Private(isolate, array));
} }
void ArrayBuffer::Private::AddRef() {
++ref_count_;
}
void ArrayBuffer::Private::Release() {
if (--ref_count_)
return;
delete this;
}
ArrayBuffer::Private::Private(v8::Isolate* isolate, ArrayBuffer::Private::Private(v8::Isolate* isolate,
v8::Handle<v8::ArrayBuffer> array) v8::Handle<v8::ArrayBuffer> array)
: ref_count_(0), : array_buffer_(isolate, array) {
array_buffer_(isolate, array) {
// Take ownership of the array buffer. // Take ownership of the array buffer.
v8::ArrayBuffer::Contents contents = array->Externalize(); v8::ArrayBuffer::Contents contents = array->Externalize();
buffer_ = contents.Data(); buffer_ = contents.Data();
...@@ -107,7 +95,7 @@ ArrayBuffer::Private::Private(v8::Isolate* isolate, ...@@ -107,7 +95,7 @@ ArrayBuffer::Private::Private(v8::Isolate* isolate,
array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this); array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this);
AddRef(); // Balanced in WeakCallback. self_reference_ = this; // Cleared in WeakCallback.
array_buffer_.SetWeak(this, WeakCallback); array_buffer_.SetWeak(this, WeakCallback);
} }
...@@ -119,7 +107,7 @@ void ArrayBuffer::Private::WeakCallback( ...@@ -119,7 +107,7 @@ void ArrayBuffer::Private::WeakCallback(
const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) { const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) {
Private* parameter = data.GetParameter(); Private* parameter = data.GetParameter();
parameter->array_buffer_.Reset(); parameter->array_buffer_.Reset();
parameter->Release(); // Balanced in ArrayBuffer::Private::Private. // parameter->self_reference_.clear();
} }
// ArrayBuffer ---------------------------------------------------------------- // ArrayBuffer ----------------------------------------------------------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/ref_counted.h" // For scoped_refptr only! #include "base/memory/ref_counted.h"
#include "gin/converter.h" #include "gin/converter.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "gin/context_holder.h" #include "gin/context_holder.h"
#include <assert.h> #include "base/logging.h"
#include "gin/per_context_data.h" #include "gin/per_context_data.h"
namespace gin { namespace gin {
...@@ -17,18 +17,17 @@ ContextHolder::~ContextHolder() { ...@@ -17,18 +17,17 @@ ContextHolder::~ContextHolder() {
v8::HandleScope handle_scope(isolate()); v8::HandleScope handle_scope(isolate());
v8::Handle<v8::Context> context = this->context(); v8::Handle<v8::Context> context = this->context();
PerContextData* data = PerContextData::From(context); data_->Detach(context);
data->Detach(context); data_.reset();
delete data;
// TODO(abarth): Figure out how to set kResetInDestructor to true. // TODO(abarth): Figure out how to set kResetInDestructor to true.
context_.Reset(); context_.Reset();
} }
void ContextHolder::SetContext(v8::Handle<v8::Context> context) { void ContextHolder::SetContext(v8::Handle<v8::Context> context) {
assert(context_.IsEmpty()); DCHECK(context_.IsEmpty());
context_.Reset(isolate_, context); context_.Reset(isolate_, context);
new PerContextData(context); // Deleted in ~ContextHolder. data_.reset(new PerContextData(context));
} }
} // namespace gin } // namespace gin
...@@ -6,11 +6,15 @@ ...@@ -6,11 +6,15 @@
#define GIN_CONTEXT_HOLDER_H_ #define GIN_CONTEXT_HOLDER_H_
#include <list> #include <list>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
namespace gin { namespace gin {
class PerContextData;
class ContextHolder { class ContextHolder {
public: public:
explicit ContextHolder(v8::Isolate* isolate); explicit ContextHolder(v8::Isolate* isolate);
...@@ -27,6 +31,7 @@ class ContextHolder { ...@@ -27,6 +31,7 @@ class ContextHolder {
private: private:
v8::Isolate* isolate_; v8::Isolate* isolate_;
v8::Persistent<v8::Context> context_; v8::Persistent<v8::Context> context_;
scoped_ptr<PerContextData> data_;
DISALLOW_COPY_AND_ASSIGN(ContextHolder); DISALLOW_COPY_AND_ASSIGN(ContextHolder);
}; };
......
...@@ -10,26 +10,29 @@ ...@@ -10,26 +10,29 @@
{ {
'target_name': 'gin', 'target_name': 'gin',
'type': 'static_library', 'type': 'static_library',
'include_dirs': [
'..'
],
'dependencies': [ 'dependencies': [
'../base/base.gyp:base',
'../v8/tools/gyp/v8.gyp:v8', '../v8/tools/gyp/v8.gyp:v8',
], ],
'export_dependent_settings': [ 'export_dependent_settings': [
'../base/base.gyp:base',
'../v8/tools/gyp/v8.gyp:v8', '../v8/tools/gyp/v8.gyp:v8',
], ],
'sources': [ 'sources': [
'modules/file_module_provider.cc',
'modules/file_module_provider.h',
'modules/module_registry.cc', 'modules/module_registry.cc',
'modules/module_registry.h', 'modules/module_registry.h',
'modules/module_runner_delegate.cc',
'modules/module_runner_delegate.h',
'arguments.cc', 'arguments.cc',
'arguments.h', 'arguments.h',
'array_buffer.cc', 'array_buffer.cc',
'array_buffer.h', 'array_buffer.h',
'converter.cc',
'converter.h',
'context_holder.cc', 'context_holder.cc',
'context_holder.h', 'context_holder.h',
'converter.cc',
'converter.h',
'dictionary.cc', 'dictionary.cc',
'dictionary.h', 'dictionary.h',
'initialize.cc', 'initialize.cc',
...@@ -40,20 +43,35 @@ ...@@ -40,20 +43,35 @@
'per_isolate_data.h', 'per_isolate_data.h',
'runner.cc', 'runner.cc',
'runner.h', 'runner.h',
'try_catch.cc',
'try_catch.h',
'wrapper_info.cc', 'wrapper_info.cc',
'wrapper_info.h', 'wrapper_info.h',
], ],
}, },
{
'target_name': 'gin_shell',
'type': 'executable',
'dependencies': [
'gin',
],
'sources': [
'shell/gin_main.cc',
],
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': '1', # /SUBSYSTEM:CONSOLE
},
},
},
{ {
'target_name': 'gin_test', 'target_name': 'gin_test',
'type': 'static_library', 'type': 'static_library',
'dependencies': [ 'dependencies': [
'../base/base.gyp:base',
'../testing/gtest.gyp:gtest', '../testing/gtest.gyp:gtest',
'gin', 'gin',
], ],
'export_dependent_settings': [ 'export_dependent_settings': [
'../base/base.gyp:base',
'../testing/gtest.gyp:gtest', '../testing/gtest.gyp:gtest',
'gin', 'gin',
], ],
......
...@@ -27,7 +27,7 @@ void Initialize() { ...@@ -27,7 +27,7 @@ void Initialize() {
v8::V8::SetArrayBufferAllocator(ArrayBufferAllocator::SharedInstance()); v8::V8::SetArrayBufferAllocator(ArrayBufferAllocator::SharedInstance());
v8::V8::InitializeICU(); v8::V8::InitializeICU();
v8::V8::SetFlagsFromString(kFlags, v8::V8::SetFlagsFromString(kFlags,
static_cast<uint32_t>(sizeof(kFlags) / sizeof(kFlags[0])) - 1); static_cast<uint32_t>(arraysize(kFlags)) - 1);
v8::V8::SetEntropySource(&GenerateEntropy); v8::V8::SetEntropySource(&GenerateEntropy);
v8::V8::Initialize(); v8::V8::Initialize();
......
// 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/file_module_provider.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_split.h"
#include "gin/converter.h"
namespace gin {
namespace {
void AttempToLoadModule(const base::WeakPtr<Runner>& runner,
const base::FilePath& base,
const std::string& id) {
if (!runner)
return;
std::vector<std::string> components;
base::SplitString(id, '/', &components);
base::FilePath path = base;
for (size_t i = 0; i < components.size(); ++i) {
// TODO(abarth): Technically the path components can be UTF-8. We don't
// handle that case correctly yet.
path = path.AppendASCII(components[i]);
}
path = path.AddExtension(FILE_PATH_LITERAL("js"));
std::string source;
if (!ReadFileToString(path, &source))
return;
Runner::Scope scope(runner.get());
v8::Handle<v8::Script> script = v8::Script::New(
StringToV8(runner->isolate(), source),
StringToV8(runner->isolate(), id));
runner->Run(script);
}
} // namespace
FileModuleProvider::FileModuleProvider(const base::FilePath& base)
: base_(base) {
}
FileModuleProvider::~FileModuleProvider() {
}
void FileModuleProvider::AttempToLoadModules(
Runner* runner, const std::set<std::string>& ids) {
std::set<std::string> modules = ids;
for (std::set<std::string>::const_iterator it = modules.begin();
it != modules.end(); ++it) {
const std::string& id = *it;
if (attempted_ids_.count(id))
continue;
attempted_ids_.insert(id);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(AttempToLoadModule, runner->GetWeakPtr(), base_, id));
}
}
} // namespace gin
// 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_FILE_MODULE_PROVIDER_H_
#define GIN_MODULES_FILE_MODULE_PROVIDER_H_
#include <set>
#include <string>
#include "base/files/file_path.h"
#include "gin/runner.h"
namespace gin {
class FileModuleProvider {
public:
explicit FileModuleProvider(const base::FilePath& base);
~FileModuleProvider();
void AttempToLoadModules(Runner* runner, const std::set<std::string>& ids);
private:
base::FilePath base_;
std::set<std::string> attempted_ids_;
DISALLOW_COPY_AND_ASSIGN(FileModuleProvider);
};
} // namespace gin
#endif // GIN_MODULES_FILE_MODULE_PROVIDER_H_
This diff is collapsed.
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
#define GIN_MODULES_MODULE_REGISTRY_H_ #define GIN_MODULES_MODULE_REGISTRY_H_
#include <list> #include <list>
#include <set>
#include <string> #include <string>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "gin/per_context_data.h" #include "gin/per_context_data.h"
namespace gin { namespace gin {
...@@ -27,6 +30,8 @@ struct PendingModule; ...@@ -27,6 +30,8 @@ struct PendingModule;
// //
class ModuleRegistry : public ContextSupplement { class ModuleRegistry : public ContextSupplement {
public: public:
virtual ~ModuleRegistry();
static ModuleRegistry* From(v8::Handle<v8::Context> context); static ModuleRegistry* From(v8::Handle<v8::Context> context);
static void RegisterGlobals(v8::Isolate* isolate, static void RegisterGlobals(v8::Isolate* isolate,
...@@ -37,25 +42,42 @@ class ModuleRegistry : public ContextSupplement { ...@@ -37,25 +42,42 @@ class ModuleRegistry : public ContextSupplement {
const std::string& id, const std::string& id,
v8::Handle<v8::ObjectTemplate> templ); v8::Handle<v8::ObjectTemplate> templ);
// Takes ownership of |pending|. The caller must have already entered // The caller must have already entered our context.
// our context. void AddPendingModule(v8::Isolate* isolate,
void AddPendingModule(v8::Isolate* isolate, PendingModule* pending); scoped_ptr<PendingModule> pending);
// The caller must have already entered our context.
void AttemptToLoadMoreModules(v8::Isolate* isolate);
const std::set<std::string>& available_modules() const {
return available_modules_;
}
const std::set<std::string>& unsatisfied_dependencies() const {
return unsatisfied_dependencies_;
}
private: private:
typedef std::list<PendingModule*> PendingModuleList; // Owning reference. typedef ScopedVector<PendingModule> PendingModuleVector;
explicit ModuleRegistry(v8::Isolate* isolate); explicit ModuleRegistry(v8::Isolate* isolate);
virtual ~ModuleRegistry();
// From ContextSupplement: // From ContextSupplement:
virtual void Detach(v8::Handle<v8::Context> context) OVERRIDE; virtual void Detach(v8::Handle<v8::Context> context) OVERRIDE;
// Takes ownership of |pending|. void Load(v8::Isolate* isolate, scoped_ptr<PendingModule> pending);
bool AttemptToLoad(v8::Isolate* isolate, PendingModule* pending); void RegisterModule(v8::Isolate* isolate,
void AttemptToLoadPendingModules(v8::Isolate* isolate); const std::string& id,
v8::Handle<v8::Value> module);
bool CheckDependencies(PendingModule* pending);
bool AttemptToLoad(v8::Isolate* isolate, scoped_ptr<PendingModule> pending);
std::set<std::string> available_modules_;
std::set<std::string> unsatisfied_dependencies_;
PendingModuleVector pending_modules_;
v8::Persistent<v8::Object> modules_; v8::Persistent<v8::Object> modules_;
PendingModuleList pending_modules_;
DISALLOW_COPY_AND_ASSIGN(ModuleRegistry); DISALLOW_COPY_AND_ASSIGN(ModuleRegistry);
}; };
......
// 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/module_runner_delegate.h"
#include "gin/modules/module_registry.h"
namespace gin {
ModuleRunnerDelegate::ModuleRunnerDelegate(const base::FilePath& module_base)
: module_provider_(module_base) {
}
ModuleRunnerDelegate::~ModuleRunnerDelegate() {
}
v8::Handle<v8::ObjectTemplate> ModuleRunnerDelegate::GetGlobalTemplate(
Runner* runner) {
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
ModuleRegistry::RegisterGlobals(runner->isolate(), templ);
return templ;
}
void ModuleRunnerDelegate::DidRunScript(Runner* runner,
v8::Handle<v8::Script> script) {
ModuleRegistry* registry = ModuleRegistry::From(runner->context());
registry->AttemptToLoadMoreModules(runner->isolate());
module_provider_.AttempToLoadModules(
runner, registry->unsatisfied_dependencies());
}
} // namespace gin
// 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_MODULE_RUNNER_DELEGATE_H_
#define GIN_MODULES_MODULE_RUNNER_DELEGATE_H_
#include "base/compiler_specific.h"
#include "gin/modules/file_module_provider.h"
#include "gin/runner.h"
namespace gin {
class ModuleRunnerDelegate : public RunnerDelegate {
public:
explicit ModuleRunnerDelegate(const base::FilePath& module_base);
virtual ~ModuleRunnerDelegate();
private:
// From RunnerDelegate:
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
Runner* runner) OVERRIDE;
virtual void DidRunScript(Runner* runner,
v8::Handle<v8::Script> script) OVERRIDE;
FileModuleProvider module_provider_;
DISALLOW_COPY_AND_ASSIGN(ModuleRunnerDelegate);
};
} // namespace gin
#endif // GIN_MODULES_MODULE_RUNNER_DELEGATE_H_
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "gin/per_context_data.h" #include "gin/per_context_data.h"
#include <assert.h> #include "base/logging.h"
#include "gin/wrapper_info.h" #include "gin/wrapper_info.h"
namespace gin { namespace gin {
...@@ -20,11 +20,11 @@ PerContextData::PerContextData(v8::Handle<v8::Context> context) { ...@@ -20,11 +20,11 @@ PerContextData::PerContextData(v8::Handle<v8::Context> context) {
} }
PerContextData::~PerContextData() { PerContextData::~PerContextData() {
assert(supplements_.empty()); DCHECK(supplements_.empty());
} }
void PerContextData::Detach(v8::Handle<v8::Context> context) { void PerContextData::Detach(v8::Handle<v8::Context> context) {
assert(From(context) == this); DCHECK(From(context) == this);
context->SetAlignedPointerInEmbedderData(kEncodedValueIndex, NULL); context->SetAlignedPointerInEmbedderData(kEncodedValueIndex, NULL);
SuplementVector supplements; SuplementVector supplements;
...@@ -33,7 +33,6 @@ void PerContextData::Detach(v8::Handle<v8::Context> context) { ...@@ -33,7 +33,6 @@ void PerContextData::Detach(v8::Handle<v8::Context> context) {
for (SuplementVector::iterator it = supplements.begin(); for (SuplementVector::iterator it = supplements.begin();
it != supplements.end(); ++it) { it != supplements.end(); ++it) {
(*it)->Detach(context); (*it)->Detach(context);
delete *it;
} }
} }
...@@ -42,8 +41,8 @@ PerContextData* PerContextData::From(v8::Handle<v8::Context> context) { ...@@ -42,8 +41,8 @@ PerContextData* PerContextData::From(v8::Handle<v8::Context> context) {
context->GetAlignedPointerFromEmbedderData(kEncodedValueIndex)); context->GetAlignedPointerFromEmbedderData(kEncodedValueIndex));
} }
void PerContextData::AddSupplement(ContextSupplement* supplement) { void PerContextData::AddSupplement(scoped_ptr<ContextSupplement> supplement) {
supplements_.push_back(supplement); supplements_.push_back(supplement.release());
} }
} // namespace gin } // namespace gin
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
#ifndef GIN_PER_CONTEXT_DATA_H_ #ifndef GIN_PER_CONTEXT_DATA_H_
#define GIN_PER_CONTEXT_DATA_H_ #define GIN_PER_CONTEXT_DATA_H_
#include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
namespace gin { namespace gin {
...@@ -31,13 +32,11 @@ class PerContextData { ...@@ -31,13 +32,11 @@ class PerContextData {
static PerContextData* From(v8::Handle<v8::Context>); static PerContextData* From(v8::Handle<v8::Context>);
void Detach(v8::Handle<v8::Context> context); void Detach(v8::Handle<v8::Context> context);
// Takes ownership of the supplement. void AddSupplement(scoped_ptr<ContextSupplement> supplement);
void AddSupplement(ContextSupplement* supplement);
private: private:
typedef std::vector<ContextSupplement*> SuplementVector; typedef ScopedVector<ContextSupplement> SuplementVector;
// Owning reference.
SuplementVector supplements_; SuplementVector supplements_;
DISALLOW_COPY_AND_ASSIGN(PerContextData); DISALLOW_COPY_AND_ASSIGN(PerContextData);
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
#include "gin/runner.h" #include "gin/runner.h"
#include "gin/converter.h" #include "gin/converter.h"
#include "gin/try_catch.h"
using v8::Context; using v8::Context;
using v8::Handle;
using v8::HandleScope; using v8::HandleScope;
using v8::Isolate; using v8::Isolate;
using v8::Object; using v8::Object;
...@@ -22,16 +22,26 @@ RunnerDelegate::RunnerDelegate() { ...@@ -22,16 +22,26 @@ RunnerDelegate::RunnerDelegate() {
RunnerDelegate::~RunnerDelegate() { RunnerDelegate::~RunnerDelegate() {
} }
Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) { v8::Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) {
return Handle<ObjectTemplate>(); return v8::Handle<ObjectTemplate>();
} }
void RunnerDelegate::DidCreateContext(Runner* runner) { void RunnerDelegate::DidCreateContext(Runner* runner) {
} }
void RunnerDelegate::WillRunScript(Runner* runner, v8::Handle<Script> script) {
}
void RunnerDelegate::DidRunScript(Runner* runner, v8::Handle<Script> script) {
}
void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) {
}
Runner::Runner(RunnerDelegate* delegate, Isolate* isolate) Runner::Runner(RunnerDelegate* delegate, Isolate* isolate)
: ContextHolder(isolate), : ContextHolder(isolate),
delegate_(delegate) { delegate_(delegate),
weak_factory_(this) {
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
SetContext(Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this))); SetContext(Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this)));
...@@ -46,8 +56,15 @@ void Runner::Run(const std::string& script) { ...@@ -46,8 +56,15 @@ void Runner::Run(const std::string& script) {
Run(Script::New(StringToV8(isolate(), script))); Run(Script::New(StringToV8(isolate(), script)));
} }
void Runner::Run(Handle<Script> script) { void Runner::Run(v8::Handle<Script> script) {
script->Run(); delegate_->WillRunScript(this, script);
{
TryCatch try_catch;
script->Run();
if (try_catch.HasCaught())
delegate_->UnhandledException(this, try_catch);
}
delegate_->DidRunScript(this, script);
} }
Runner::Scope::Scope(Runner* runner) Runner::Scope::Scope(Runner* runner)
......
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
#define GIN_RUNNER_H_ #define GIN_RUNNER_H_
#include <string> #include <string>
#include "base/memory/weak_ptr.h"
#include "gin/context_holder.h" #include "gin/context_holder.h"
namespace gin { namespace gin {
class Runner; class Runner;
class TryCatch;
class RunnerDelegate { class RunnerDelegate {
public: public:
...@@ -19,8 +22,10 @@ class RunnerDelegate { ...@@ -19,8 +22,10 @@ class RunnerDelegate {
// Returns the template for the global object. // Returns the template for the global object.
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(Runner* runner); virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(Runner* runner);
virtual void DidCreateContext(Runner* runner); virtual void DidCreateContext(Runner* runner);
virtual void WillRunScript(Runner* runner, v8::Handle<v8::Script> script);
virtual void DidRunScript(Runner* runner, v8::Handle<v8::Script> script);
virtual void UnhandledException(Runner* runner, TryCatch& try_catch);
}; };
class Runner : public ContextHolder { class Runner : public ContextHolder {
...@@ -35,6 +40,10 @@ class Runner : public ContextHolder { ...@@ -35,6 +40,10 @@ class Runner : public ContextHolder {
return context()->Global(); return context()->Global();
} }
base::WeakPtr<Runner> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
class Scope { class Scope {
public: public:
explicit Scope(Runner* runner); explicit Scope(Runner* runner);
...@@ -52,6 +61,8 @@ class Runner : public ContextHolder { ...@@ -52,6 +61,8 @@ class Runner : public ContextHolder {
RunnerDelegate* delegate_; RunnerDelegate* delegate_;
base::WeakPtrFactory<Runner> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Runner); DISALLOW_COPY_AND_ASSIGN(Runner);
}; };
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "gin/converter.h" #include "gin/converter.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using v8::Handle;
using v8::Isolate; using v8::Isolate;
using v8::Object; using v8::Object;
using v8::Script; using v8::Script;
......
// 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/at_exit.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop/message_loop.h"
#include "gin/initialize.h"
#include "gin/modules/module_runner_delegate.h"
#include "gin/test/file_runner.h"
#include "gin/try_catch.h"
namespace gin {
namespace {
std::string Load(const base::FilePath& path) {
std::string source;
if (!ReadFileToString(path, &source))
LOG(FATAL) << "Unable to read " << path.LossyDisplayName();
return source;
}
void Run(base::WeakPtr<Runner> runner, const std::string& source) {
if (!runner)
return;
Runner::Scope scope(runner.get());
runner->Run(source);
}
base::FilePath GetModuleBase() {
base::FilePath module_base;
CHECK(file_util::GetCurrentDirectory(&module_base));
return module_base;
}
class ShellRunnerDelegate : public ModuleRunnerDelegate {
public:
ShellRunnerDelegate() : ModuleRunnerDelegate(GetModuleBase()) {}
virtual void UnhandledException(Runner* runner,
TryCatch& try_catch) OVERRIDE {
ModuleRunnerDelegate::UnhandledException(runner, try_catch);
LOG(ERROR) << try_catch.GetPrettyMessage();
}
private:
DISALLOW_COPY_AND_ASSIGN(ShellRunnerDelegate);
};
} // namespace
} // namespace gin
int main(int argc, char** argv) {
base::AtExitManager at_exit;
CommandLine::Init(argc, argv);
gin::Initialize();
base::MessageLoop message_loop;
gin::ShellRunnerDelegate delegate;
gin::Runner runner(&delegate, v8::Isolate::GetCurrent());
CommandLine::StringVector args = CommandLine::ForCurrentProcess()->GetArgs();
for (CommandLine::StringVector::const_iterator it = args.begin();
it != args.end(); ++it) {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
gin::Run, runner.GetWeakPtr(), gin::Load(base::FilePath(*it))));
}
message_loop.RunUntilIdle();
return 0;
}
...@@ -5,37 +5,36 @@ ...@@ -5,37 +5,36 @@
#include "gin/test/file_runner.h" #include "gin/test/file_runner.h"
#include "base/file_util.h" #include "base/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "gin/converter.h" #include "gin/converter.h"
#include "gin/modules/module_registry.h" #include "gin/modules/module_registry.h"
#include "gin/test/gtest.h" #include "gin/test/gtest.h"
#include "gin/try_catch.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace gin { namespace gin {
namespace { namespace {
std::string GetExceptionInfo(const v8::TryCatch& try_catch) { base::FilePath GetModuleBase() {
std::string info; base::FilePath path;
ConvertFromV8(try_catch.Message()->Get(), &info); PathService::Get(base::DIR_SOURCE_ROOT, &path);
return info; return path;
} }
} // namespace } // namespace
FileRunnerDelegate::FileRunnerDelegate() { FileRunnerDelegate::FileRunnerDelegate()
: ModuleRunnerDelegate(GetModuleBase()) {
} }
FileRunnerDelegate::~FileRunnerDelegate() { FileRunnerDelegate::~FileRunnerDelegate() {
} }
v8::Handle<v8::ObjectTemplate> FileRunnerDelegate::GetGlobalTemplate(
Runner* runner) {
v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
ModuleRegistry::RegisterGlobals(runner->isolate(), templ);
return templ;
}
void FileRunnerDelegate::DidCreateContext(Runner* runner) { void FileRunnerDelegate::DidCreateContext(Runner* runner) {
ModuleRunnerDelegate::DidCreateContext(runner);
v8::Handle<v8::Context> context = runner->context(); v8::Handle<v8::Context> context = runner->context();
ModuleRegistry* registry = ModuleRegistry::From(context); ModuleRegistry* registry = ModuleRegistry::From(context);
...@@ -43,16 +42,24 @@ void FileRunnerDelegate::DidCreateContext(Runner* runner) { ...@@ -43,16 +42,24 @@ void FileRunnerDelegate::DidCreateContext(Runner* runner) {
GetGTestTemplate(runner->isolate())); GetGTestTemplate(runner->isolate()));
} }
void FileRunnerDelegate::UnhandledException(Runner* runner,
TryCatch& try_catch) {
ModuleRunnerDelegate::UnhandledException(runner, try_catch);
EXPECT_FALSE(try_catch.HasCaught()) << try_catch.GetPrettyMessage();
}
void RunTestFromFile(const base::FilePath& path, RunnerDelegate* delegate) { void RunTestFromFile(const base::FilePath& path, RunnerDelegate* delegate) {
ASSERT_TRUE(base::PathExists(path)) << path.LossyDisplayName(); ASSERT_TRUE(base::PathExists(path)) << path.LossyDisplayName();
std::string source; std::string source;
ASSERT_TRUE(ReadFileToString(path, &source)); ASSERT_TRUE(ReadFileToString(path, &source));
base::MessageLoop message_loop;
gin::Runner runner(delegate, v8::Isolate::GetCurrent()); gin::Runner runner(delegate, v8::Isolate::GetCurrent());
gin::Runner::Scope scope(&runner); gin::Runner::Scope scope(&runner);
v8::TryCatch try_catch;
runner.Run(source); runner.Run(source);
EXPECT_FALSE(try_catch.HasCaught()) << GetExceptionInfo(try_catch);
message_loop.RunUntilIdle();
v8::Handle<v8::Value> result = runner.context()->Global()->Get( v8::Handle<v8::Value> result = runner.context()->Global()->Get(
StringToSymbol(runner.isolate(), "result")); StringToSymbol(runner.isolate(), "result"));
......
...@@ -7,19 +7,21 @@ ...@@ -7,19 +7,21 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "gin/modules/module_runner_delegate.h"
#include "gin/runner.h" #include "gin/runner.h"
namespace gin { namespace gin {
class FileRunnerDelegate : public RunnerDelegate { class FileRunnerDelegate : public ModuleRunnerDelegate {
public: public:
FileRunnerDelegate(); FileRunnerDelegate();
virtual ~FileRunnerDelegate(); virtual ~FileRunnerDelegate();
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
Runner* runner) OVERRIDE;
virtual void DidCreateContext(Runner* runner) OVERRIDE;
private: private:
// From ModuleRunnerDelegate:
virtual void DidCreateContext(Runner* runner) OVERRIDE;
virtual void UnhandledException(Runner* runner, TryCatch& try_catch) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(FileRunnerDelegate); DISALLOW_COPY_AND_ASSIGN(FileRunnerDelegate);
}; };
......
// 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/try_catch.h"
#include "gin/converter.h"
namespace gin {
TryCatch::TryCatch() {
}
TryCatch::~TryCatch() {
}
bool TryCatch::HasCaught() {
return try_catch_.HasCaught();
}
std::string TryCatch::GetPrettyMessage() {
std::string info;
ConvertFromV8(try_catch_.Message()->Get(), &info);
std::string sounce_line;
if (ConvertFromV8(try_catch_.Message()->GetSourceLine(), &sounce_line))
info += "\n" + sounce_line;
return info;
}
} // namespace gin
// 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_EXCEPTION_H_
#define GIN_EXCEPTION_H_
#include <string>
#include "base/basictypes.h"
#include "v8/include/v8.h"
namespace gin {
class TryCatch {
public:
TryCatch();
~TryCatch();
bool HasCaught();
std::string GetPrettyMessage();
private:
v8::TryCatch try_catch_;
DISALLOW_COPY_AND_ASSIGN(TryCatch);
};
} // namespace gin
#endif // GIN_EXCEPTION_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment