summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gin/modules/module_registry.cc47
-rw-r--r--gin/modules/module_runner_delegate.cc3
-rw-r--r--gin/modules/module_runner_delegate.h3
-rw-r--r--gin/per_context_data.cc3
-rw-r--r--gin/per_context_data.h6
-rw-r--r--gin/per_isolate_data.cc1
-rw-r--r--gin/runner.cc35
-rw-r--r--gin/runner.h9
-rw-r--r--gin/wrappable.cc6
-rw-r--r--gin/wrappable.h2
-rw-r--r--mojo/apps/js/DEPS1
-rw-r--r--mojo/apps/js/bootstrap.cc54
-rw-r--r--mojo/apps/js/bootstrap.h26
-rw-r--r--mojo/apps/js/main.cc32
-rw-r--r--mojo/apps/js/main.js29
-rw-r--r--mojo/apps/js/mojo_runner_delegate.cc50
-rw-r--r--mojo/apps/js/mojo_runner_delegate.h30
-rw-r--r--mojo/mojo.gyp16
-rw-r--r--mojo/public/bindings/js/codec.js1
-rw-r--r--mojo/public/bindings/js/connector.js98
-rw-r--r--mojo/public/bindings/js/support.cc86
-rw-r--r--mojo/public/bindings/js/support.h22
-rw-r--r--mojo/public/bindings/js/waiting_callback.cc72
-rw-r--r--mojo/public/bindings/js/waiting_callback.h56
24 files changed, 642 insertions, 46 deletions
diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc
index afb07d3..d868dec 100644
--- a/gin/modules/module_registry.cc
+++ b/gin/modules/module_registry.cc
@@ -12,13 +12,12 @@
#include "gin/converter.h"
#include "gin/per_isolate_data.h"
#include "gin/public/wrapper_info.h"
-#include "gin/try_catch.h"
+#include "gin/runner.h"
using v8::Context;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
-using v8::Handle;
using v8::Isolate;
using v8::Local;
using v8::Object;
@@ -56,7 +55,7 @@ void Define(const v8::FunctionCallbackInfo<Value>& info) {
std::string id;
std::vector<std::string> dependencies;
- Handle<Value> factory;
+ v8::Handle<Value> factory;
if (args.PeekNext()->IsString())
args.GetNext(&id);
@@ -88,7 +87,7 @@ Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) {
return templ;
}
-Handle<String> GetHiddenValueKey(Isolate* isolate) {
+v8::Handle<String> GetHiddenValueKey(Isolate* isolate) {
return StringToSymbol(isolate, "::gin::ModuleRegistry");
}
@@ -103,15 +102,15 @@ ModuleRegistry::~ModuleRegistry() {
}
void ModuleRegistry::RegisterGlobals(Isolate* isolate,
- Handle<ObjectTemplate> templ) {
+ v8::Handle<ObjectTemplate> templ) {
templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate));
}
-ModuleRegistry* ModuleRegistry::From(Handle<Context> context) {
+ModuleRegistry* ModuleRegistry::From(v8::Handle<Context> context) {
Isolate* isolate = context->GetIsolate();
- Handle<String> key = GetHiddenValueKey(isolate);
- Handle<Value> value = context->Global()->GetHiddenValue(key);
- Handle<External> external;
+ v8::Handle<String> key = GetHiddenValueKey(isolate);
+ v8::Handle<Value> value = context->Global()->GetHiddenValue(key);
+ v8::Handle<External> external;
if (value.IsEmpty() || !ConvertFromV8(value, &external)) {
PerContextData* data = PerContextData::From(context);
if (!data)
@@ -126,7 +125,7 @@ ModuleRegistry* ModuleRegistry::From(Handle<Context> context) {
void ModuleRegistry::AddBuiltinModule(Isolate* isolate,
const std::string& id,
- Handle<ObjectTemplate> templ) {
+ v8::Handle<ObjectTemplate> templ) {
DCHECK(!id.empty());
RegisterModule(isolate, id, templ->NewInstance());
}
@@ -138,19 +137,19 @@ void ModuleRegistry::AddPendingModule(Isolate* isolate,
void ModuleRegistry::RegisterModule(Isolate* isolate,
const std::string& id,
- Handle<Value> module) {
+ v8::Handle<Value> module) {
if (id.empty() || module.IsEmpty())
return;
unsatisfied_dependencies_.erase(id);
available_modules_.insert(id);
- Handle<Object> modules = Local<Object>::New(isolate, modules_);
+ v8::Handle<Object> modules = Local<Object>::New(isolate, modules_);
modules->Set(StringToSymbol(isolate, id), module);
}
-void ModuleRegistry::Detach(Handle<Context> context) {
+void ModuleRegistry::Detach(v8::Handle<Context> context) {
context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()),
- Handle<Value>());
+ v8::Handle<Value>());
}
bool ModuleRegistry::CheckDependencies(PendingModule* pending) {
@@ -170,26 +169,22 @@ void ModuleRegistry::Load(Isolate* isolate, scoped_ptr<PendingModule> pending) {
if (!pending->id.empty() && available_modules_.count(pending->id))
return; // We've already loaded this module.
- Handle<Object> modules = Local<Object>::New(isolate, modules_);
+ v8::Handle<Object> modules = Local<Object>::New(isolate, modules_);
uint32_t argc = static_cast<uint32_t>(pending->dependencies.size());
- std::vector<Handle<Value> > argv(argc);
+ std::vector<v8::Handle<Value> > argv(argc);
for (uint32_t i = 0; i < argc; ++i) {
- Handle<String> key = StringToSymbol(isolate, pending->dependencies[i]);
+ v8::Handle<String> key = StringToSymbol(isolate, pending->dependencies[i]);
DCHECK(modules->HasOwnProperty(key));
argv[i] = modules->Get(key);
}
- Handle<Value> module = Local<Value>::New(isolate, pending->factory);
+ v8::Handle<Value> module = Local<Value>::New(isolate, pending->factory);
- Handle<Function> factory;
+ v8::Handle<Function> factory;
if (ConvertFromV8(module, &factory)) {
- Handle<Object> global = isolate->GetCurrentContext()->Global();
- {
- gin::TryCatch try_catch;
- module = factory->Call(global, argc, argv.data());
- if (try_catch.HasCaught())
- return; // TODO(abarth): What should we do with the exception?
- }
+ PerContextData* data = PerContextData::From(isolate->GetCurrentContext());
+ Runner* runner = data->runner();
+ module = runner->Call(factory, runner->global(), argc, argv.data());
if (pending->id.empty())
ConvertFromV8(factory->GetScriptOrigin().ResourceName(), &pending->id);
}
diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc
index 3f2422c..9e0b762 100644
--- a/gin/modules/module_runner_delegate.cc
+++ b/gin/modules/module_runner_delegate.cc
@@ -41,8 +41,7 @@ void ModuleRunnerDelegate::DidCreateContext(Runner* runner) {
}
}
-void ModuleRunnerDelegate::DidRunScript(Runner* runner,
- v8::Handle<v8::Script> script) {
+void ModuleRunnerDelegate::DidRunScript(Runner* runner) {
ModuleRegistry* registry = ModuleRegistry::From(runner->context());
registry->AttemptToLoadMoreModules(runner->isolate());
module_provider_.AttempToLoadModules(
diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h
index a66695f..efc9761 100644
--- a/gin/modules/module_runner_delegate.h
+++ b/gin/modules/module_runner_delegate.h
@@ -31,8 +31,7 @@ class ModuleRunnerDelegate : public RunnerDelegate {
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
Runner* runner) OVERRIDE;
virtual void DidCreateContext(Runner* runner) OVERRIDE;
- virtual void DidRunScript(Runner* runner,
- v8::Handle<v8::Script> script) OVERRIDE;
+ virtual void DidRunScript(Runner* runner) OVERRIDE;
BuiltinModuleMap builtin_modules_;
FileModuleProvider module_provider_;
diff --git a/gin/per_context_data.cc b/gin/per_context_data.cc
index 4a76616..666c414 100644
--- a/gin/per_context_data.cc
+++ b/gin/per_context_data.cc
@@ -15,7 +15,8 @@ ContextSupplement::ContextSupplement() {
ContextSupplement::~ContextSupplement() {
}
-PerContextData::PerContextData(v8::Handle<v8::Context> context) {
+PerContextData::PerContextData(v8::Handle<v8::Context> context)
+ : runner_(NULL) {
context->SetAlignedPointerInEmbedderData(kEncodedValueIndex, this);
}
diff --git a/gin/per_context_data.h b/gin/per_context_data.h
index 0f10485..b89c5a6 100644
--- a/gin/per_context_data.h
+++ b/gin/per_context_data.h
@@ -12,6 +12,8 @@
namespace gin {
+class Runner;
+
class ContextSupplement {
public:
ContextSupplement();
@@ -32,11 +34,15 @@ class PerContextData {
static PerContextData* From(v8::Handle<v8::Context>);
void Detach(v8::Handle<v8::Context> context);
+ void set_runner(Runner* runner) { runner_ = runner; }
+ Runner* runner() const { return runner_; }
+
void AddSupplement(scoped_ptr<ContextSupplement> supplement);
private:
typedef ScopedVector<ContextSupplement> SuplementVector;
+ Runner* runner_;
SuplementVector supplements_;
DISALLOW_COPY_AND_ASSIGN(PerContextData);
diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc
index 844f1e1..6c2397b 100644
--- a/gin/per_isolate_data.cc
+++ b/gin/per_isolate_data.cc
@@ -6,7 +6,6 @@
#include "gin/public/gin_embedders.h"
using v8::Eternal;
-using v8::Handle;
using v8::Isolate;
using v8::Local;
using v8::Object;
diff --git a/gin/runner.cc b/gin/runner.cc
index f45d6a0..0cd7269 100644
--- a/gin/runner.cc
+++ b/gin/runner.cc
@@ -5,6 +5,7 @@
#include "gin/runner.h"
#include "gin/converter.h"
+#include "gin/per_context_data.h"
#include "gin/try_catch.h"
using v8::Context;
@@ -29,10 +30,10 @@ v8::Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) {
void RunnerDelegate::DidCreateContext(Runner* runner) {
}
-void RunnerDelegate::WillRunScript(Runner* runner, v8::Handle<Script> script) {
+void RunnerDelegate::WillRunScript(Runner* runner) {
}
-void RunnerDelegate::DidRunScript(Runner* runner, v8::Handle<Script> script) {
+void RunnerDelegate::DidRunScript(Runner* runner) {
}
void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) {
@@ -44,9 +45,13 @@ Runner::Runner(RunnerDelegate* delegate, Isolate* isolate)
weak_factory_(this) {
v8::Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
- SetContext(Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this)));
+ v8::Handle<v8::Context> context =
+ Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this));
- v8::Context::Scope scope(context());
+ SetContext(context);
+ PerContextData::From(context)->set_runner(this);
+
+ v8::Context::Scope scope(context);
delegate_->DidCreateContext(this);
}
@@ -59,13 +64,31 @@ void Runner::Run(const std::string& script) {
void Runner::Run(v8::Handle<Script> script) {
TryCatch try_catch;
- delegate_->WillRunScript(this, script);
+ delegate_->WillRunScript(this);
+
script->Run();
- delegate_->DidRunScript(this, script);
+
+ delegate_->DidRunScript(this);
if (try_catch.HasCaught())
delegate_->UnhandledException(this, try_catch);
}
+v8::Handle<v8::Value> Runner::Call(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Value> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]) {
+ TryCatch try_catch;
+ delegate_->WillRunScript(this);
+
+ v8::Handle<v8::Value> result = function->Call(receiver, argc, argv);
+
+ delegate_->DidRunScript(this);
+ if (try_catch.HasCaught())
+ delegate_->UnhandledException(this, try_catch);
+
+ return result;
+}
+
Runner::Scope::Scope(Runner* runner)
: isolate_scope_(runner->isolate()),
handle_scope_(runner->isolate()),
diff --git a/gin/runner.h b/gin/runner.h
index e664c3d..614b60d 100644
--- a/gin/runner.h
+++ b/gin/runner.h
@@ -23,8 +23,8 @@ class RunnerDelegate {
// Returns the template for the global object.
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(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 WillRunScript(Runner* runner);
+ virtual void DidRunScript(Runner* runner);
virtual void UnhandledException(Runner* runner, TryCatch& try_catch);
};
@@ -36,6 +36,11 @@ class Runner : public ContextHolder {
void Run(const std::string& script);
void Run(v8::Handle<v8::Script> script);
+ v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Value> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]);
+
v8::Handle<v8::Object> global() const {
return context()->Global();
}
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
index 980349a..943927b 100644
--- a/gin/wrappable.cc
+++ b/gin/wrappable.cc
@@ -16,6 +16,12 @@ Wrappable::~Wrappable() {
wrapper_.Reset();
}
+v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) {
+ v8::Handle<v8::Value> wrapper = ConvertToV8(isolate, this);
+ DCHECK(wrapper->IsObject());
+ return v8::Handle<v8::Object>::Cast(wrapper);
+}
+
void Wrappable::WeakCallback(
const v8::WeakCallbackData<v8::Object, Wrappable>& data) {
Wrappable* wrappable = data.GetParameter();
diff --git a/gin/wrappable.h b/gin/wrappable.h
index 66c2389..79b7144 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -15,6 +15,8 @@ class Wrappable : public base::RefCounted<Wrappable> {
public:
virtual WrapperInfo* GetWrapperInfo() = 0;
+ v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate);
+
protected:
Wrappable();
virtual ~Wrappable();
diff --git a/mojo/apps/js/DEPS b/mojo/apps/js/DEPS
index 0b70f92..d974b68 100644
--- a/mojo/apps/js/DEPS
+++ b/mojo/apps/js/DEPS
@@ -1,5 +1,4 @@
include_rules = [
"+gin",
"+v8",
- "-base",
]
diff --git a/mojo/apps/js/bootstrap.cc b/mojo/apps/js/bootstrap.cc
new file mode 100644
index 0000000..f724b2d
--- /dev/null
+++ b/mojo/apps/js/bootstrap.cc
@@ -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.
+
+#include "mojo/apps/js/bootstrap.h"
+
+#include "base/message_loop/message_loop.h"
+#include "gin/per_isolate_data.h"
+#include "mojo/public/bindings/js/handle.h"
+
+namespace mojo {
+namespace apps {
+
+namespace {
+
+void Quit(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ base::MessageLoop::current()->QuitNow();
+}
+
+MojoHandle g_initial_handle = MOJO_HANDLE_INVALID;
+
+gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
+
+} // namespace
+
+const char Bootstrap::kModuleName[] = "mojo/apps/js/bootstrap";
+
+v8::Local<v8::ObjectTemplate> Bootstrap::GetTemplate(v8::Isolate* isolate) {
+ gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
+ v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
+ &g_wrapper_info);
+
+ if (templ.IsEmpty()) {
+ templ = v8::ObjectTemplate::New();
+ templ->Set(gin::StringToSymbol(isolate, "quit"),
+ v8::FunctionTemplate::New(Quit));
+
+ // Don't forget to call SetInitialHandle before getting the template.
+ DCHECK(g_initial_handle != MOJO_HANDLE_INVALID);
+ templ->Set(gin::StringToSymbol(isolate, "initialHandle"),
+ gin::ConvertToV8(isolate, g_initial_handle));
+
+ data->SetObjectTemplate(&g_wrapper_info, templ);
+ }
+
+ return templ;
+}
+
+void Bootstrap::SetInitialHandle(MojoHandle pipe) {
+ g_initial_handle = pipe;
+}
+
+} // namespace apps
+} // namespace mojo
diff --git a/mojo/apps/js/bootstrap.h b/mojo/apps/js/bootstrap.h
new file mode 100644
index 0000000..4355760a
--- /dev/null
+++ b/mojo/apps/js/bootstrap.h
@@ -0,0 +1,26 @@
+// 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 MOJO_APPS_JS_BOOTSTRAP_H_
+#define MOJO_APPS_JS_BOOTSTRAP_H_
+
+#include "mojo/public/system/core.h"
+#include "v8/include/v8.h"
+
+namespace mojo {
+namespace apps {
+
+class Bootstrap {
+ public:
+ static const char kModuleName[];
+ static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate);
+
+ // Must be called before the first call to GetTemplate.
+ static void SetInitialHandle(MojoHandle handle);
+};
+
+} // namespace apps
+} // namespace mojo
+
+#endif // MOJO_APPS_JS_BOOTSTRAP_H_
diff --git a/mojo/apps/js/main.cc b/mojo/apps/js/main.cc
index 1ad084b..0706182 100644
--- a/mojo/apps/js/main.cc
+++ b/mojo/apps/js/main.cc
@@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/message_loop/message_loop.h"
#include "gin/public/isolate_holder.h"
+#include "mojo/apps/js/bootstrap.h"
+#include "mojo/apps/js/mojo_runner_delegate.h"
+#include "mojo/common/bindings_support_impl.h"
#include "mojo/public/system/core_cpp.h"
#include "mojo/public/system/macros.h"
@@ -16,8 +20,32 @@
#define MOJO_APPS_JS_EXPORT __attribute__((visibility("default")))
#endif
-extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) {
+namespace mojo {
+namespace apps {
+
+void RunMojoJS(MojoHandle pipe) {
gin::IsolateHolder instance;
- // TODO(abarth): Load JS off the network and execute it.
+ Bootstrap::SetInitialHandle(pipe);
+
+ MojoRunnerDelegate delegate;
+ gin::Runner runner(&delegate, instance.isolate());
+
+ {
+ gin::Runner::Scope scope(&runner);
+ runner.Run("define(['mojo/apps/js/main'], function(main) {});");
+ }
+
+ base::MessageLoop::current()->Run();
+}
+
+} // namespace apps
+} // namespace mojo
+
+extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) {
+ base::MessageLoop loop;
+ mojo::common::BindingsSupportImpl bindings_support;
+ mojo::BindingsSupport::Set(&bindings_support);
+ mojo::apps::RunMojoJS(pipe);
+ mojo::BindingsSupport::Set(NULL);
return MOJO_RESULT_OK;
}
diff --git a/mojo/apps/js/main.js b/mojo/apps/js/main.js
new file mode 100644
index 0000000..a04048a
--- /dev/null
+++ b/mojo/apps/js/main.js
@@ -0,0 +1,29 @@
+// 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.
+
+define([
+ "console",
+ "mojo/apps/js/bootstrap",
+ "mojo/public/bindings/js/connector",
+ "mojom/hello_world_service",
+], function(console, bootstrap, connector, hello) {
+
+ function HelloWorldClientImpl() {
+ }
+
+ HelloWorldClientImpl.prototype =
+ Object.create(hello.HelloWorldClientStub.prototype);
+
+ HelloWorldClientImpl.prototype.didReceiveGreeting = function(result) {
+ console.log("DidReceiveGreeting from pipe: " + result);
+ connection.close();
+ bootstrap.quit();
+ };
+
+ var connection = new connector.Connection(bootstrap.initialHandle,
+ HelloWorldClientImpl,
+ hello.HelloWorldServiceProxy);
+
+ connection.remote.greeting("hello, world!");
+});
diff --git a/mojo/apps/js/mojo_runner_delegate.cc b/mojo/apps/js/mojo_runner_delegate.cc
new file mode 100644
index 0000000..ba085e5
--- /dev/null
+++ b/mojo/apps/js/mojo_runner_delegate.cc
@@ -0,0 +1,50 @@
+// 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 "mojo/apps/js/mojo_runner_delegate.h"
+
+#include "base/path_service.h"
+#include "gin/modules/console.h"
+#include "gin/modules/module_registry.h"
+#include "gin/try_catch.h"
+#include "mojo/apps/js/bootstrap.h"
+#include "mojo/public/bindings/js/core.h"
+#include "mojo/public/bindings/js/support.h"
+
+namespace mojo {
+namespace apps {
+
+namespace {
+
+// TODO(abarth): Rather than loading these modules from the file system, we
+// should load them from the network via Mojo IPC.
+std::vector<base::FilePath> GetModuleSearchPaths() {
+ std::vector<base::FilePath> search_paths(2);
+ PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]);
+ PathService::Get(base::DIR_EXE, &search_paths[1]);
+ search_paths[1] = search_paths[1].AppendASCII("gen");
+ return search_paths;
+}
+
+} // namespace
+
+MojoRunnerDelegate::MojoRunnerDelegate()
+ : ModuleRunnerDelegate(GetModuleSearchPaths()) {
+ AddBuiltinModule(Bootstrap::kModuleName, Bootstrap::GetTemplate);
+ AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetTemplate);
+ AddBuiltinModule(js::Core::kModuleName, js::Core::GetTemplate);
+ AddBuiltinModule(js::Support::kModuleName, js::Support::GetTemplate);
+}
+
+MojoRunnerDelegate::~MojoRunnerDelegate() {
+}
+
+void MojoRunnerDelegate::UnhandledException(gin::Runner* runner,
+ gin::TryCatch& try_catch) {
+ gin::ModuleRunnerDelegate::UnhandledException(runner, try_catch);
+ LOG(ERROR) << try_catch.GetPrettyMessage();
+}
+
+} // namespace apps
+} // namespace mojo
diff --git a/mojo/apps/js/mojo_runner_delegate.h b/mojo/apps/js/mojo_runner_delegate.h
new file mode 100644
index 0000000..899ef01
--- /dev/null
+++ b/mojo/apps/js/mojo_runner_delegate.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 MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_
+#define MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "gin/modules/module_runner_delegate.h"
+
+namespace mojo {
+namespace apps {
+
+class MojoRunnerDelegate : public gin::ModuleRunnerDelegate {
+ public:
+ MojoRunnerDelegate();
+ virtual ~MojoRunnerDelegate();
+
+ private:
+ // From ModuleRunnerDelegate:
+ virtual void UnhandledException(gin::Runner* runner,
+ gin::TryCatch& try_catch) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoRunnerDelegate);
+};
+
+} // namespace apps
+} // namespace mojo
+
+#endif // MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index 9cdd14b..494a523 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -291,14 +291,20 @@
{
'target_name': 'mojo_js',
'type': 'shared_library',
- 'include_dirs': [
- '..'
- ],
'dependencies': [
+ '../base/base.gyp:base',
+ '../gin/gin.gyp:gin',
+ 'hello_world_service',
+ 'mojo_common_lib',
'mojo_js_bindings',
+ 'mojo_system',
],
'sources': [
+ 'apps/js/bootstrap.cc',
+ 'apps/js/bootstrap.h',
'apps/js/main.cc',
+ 'apps/js/mojo_runner_delegate.cc',
+ 'apps/js/mojo_runner_delegate.h',
],
},
{
@@ -428,6 +434,10 @@
'public/bindings/js/core.h',
'public/bindings/js/handle.cc',
'public/bindings/js/handle.h',
+ 'public/bindings/js/support.cc',
+ 'public/bindings/js/support.h',
+ 'public/bindings/js/waiting_callback.cc',
+ 'public/bindings/js/waiting_callback.h',
],
},
{
diff --git a/mojo/public/bindings/js/codec.js b/mojo/public/bindings/js/codec.js
index 2b3f86c..0245de4 100644
--- a/mojo/public/bindings/js/codec.js
+++ b/mojo/public/bindings/js/codec.js
@@ -428,6 +428,7 @@ define(function() {
var exports = {};
exports.align = align;
+ exports.Message = Message;
exports.MessageBuilder = MessageBuilder;
exports.MessageReader = MessageReader;
exports.kArrayHeaderSize = kArrayHeaderSize;
diff --git a/mojo/public/bindings/js/connector.js b/mojo/public/bindings/js/connector.js
new file mode 100644
index 0000000..c9d0566
--- /dev/null
+++ b/mojo/public/bindings/js/connector.js
@@ -0,0 +1,98 @@
+// 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.
+
+define([
+ "mojo/public/bindings/js/codec",
+ "mojo/public/bindings/js/core",
+ "mojo/public/bindings/js/support",
+], function(codec, core, support) {
+
+ function Connector(handle) {
+ this.handle_ = handle;
+ this.error_ = false;
+ this.incomingReceiver_ = null;
+ this.readWaitCookie_ = null;
+ }
+
+ Connector.prototype.close = function() {
+ if (this.readWaitCookie_) {
+ support.cancelWait(this.readWaitCookie_);
+ this.readWaitCookie_ = null;
+ }
+ if (this.handle_ != core.kInvalidHandle) {
+ core.close(this.handle_);
+ this.handle_ = core.kInvalidHandle;
+ }
+ };
+
+ Connector.prototype.accept = function(message) {
+ if (this.error_)
+ return false;
+ this.write_(message);
+ return !this.error_;
+ };
+
+ Connector.prototype.setIncomingReceiver = function(receiver) {
+ this.incomingReceiver_ = receiver;
+ if (this.incomingReceiver_)
+ this.waitToReadMore_();
+ };
+
+ Connector.prototype.write_ = function(message) {
+ var result = core.writeMessage(this.handle_,
+ message.memory,
+ message.handles,
+ core.WRITE_MESSAGE_FLAG_NONE);
+ if (result != core.RESULT_OK) {
+ this.error_ = true
+ return;
+ }
+ // The handles were successfully transferred, so we don't own them anymore.
+ message.handles = [];
+ };
+
+ Connector.prototype.waitToReadMore_ = function() {
+ this.readWaitCookie_ = support.asyncWait(this.handle_,
+ core.WAIT_FLAG_READABLE,
+ this.readMore_.bind(this));
+ };
+
+ Connector.prototype.readMore_ = function(result) {
+ for (;;) {
+ var read = core.readMessage(this.handle_,
+ core.READ_MESSAGE_FLAG_NONE);
+ if (read.result == core.RESULT_NOT_FOUND) {
+ this.waitToReadMore_();
+ return;
+ }
+ if (read.result != core.RESULT_OK) {
+ this.error_ = true;
+ return;
+ }
+ // TODO(abarth): Should core.readMessage return a Uint8Array?
+ var memory = new Uint8Array(read.buffer);
+ var message = new codec.Message(memory, read.handles);
+ this.incomingReceiver_.accept(message);
+ }
+ };
+
+ function Connection(handle, localFactory, remoteFactory) {
+ this.connector_ = new Connector(handle);
+ this.local = new localFactory();
+ this.remote = new remoteFactory(this.connector_);
+
+ this.connector_.setIncomingReceiver(this.local);
+ }
+
+ Connection.prototype.close = function() {
+ this.connector_.close();
+ this.connector_ = null;
+ this.local = null;
+ this.remote = null;
+ };
+
+ var exports = {};
+ exports.Connection = Connection;
+ return exports;
+});
diff --git a/mojo/public/bindings/js/support.cc b/mojo/public/bindings/js/support.cc
new file mode 100644
index 0000000..da279f3
--- /dev/null
+++ b/mojo/public/bindings/js/support.cc
@@ -0,0 +1,86 @@
+// 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 "mojo/public/bindings/js/support.h"
+
+#include "gin/arguments.h"
+#include "gin/converter.h"
+#include "gin/per_isolate_data.h"
+#include "gin/public/wrapper_info.h"
+#include "gin/wrappable.h"
+#include "mojo/public/bindings/js/handle.h"
+#include "mojo/public/bindings/js/waiting_callback.h"
+#include "mojo/public/bindings/lib/bindings_support.h"
+
+namespace mojo {
+namespace js {
+
+namespace {
+
+void AsyncWait(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle;
+ MojoWaitFlags flags = MOJO_WAIT_FLAG_NONE;
+ v8::Handle<v8::Function> callback;
+
+ if (!args.GetNext(&handle) ||
+ !args.GetNext(&flags) ||
+ !args.GetNext(&callback))
+ return args.ThrowError();
+
+ scoped_refptr<WaitingCallback> waiting_callback =
+ WaitingCallback::Create(args.isolate(), callback);
+
+ BindingsSupport::AsyncWaitID wait_id = BindingsSupport::Get()->AsyncWait(
+ handle, flags, waiting_callback.get());
+
+ waiting_callback->set_wait_id(wait_id);
+
+ args.Return(waiting_callback.get());
+}
+
+void CancelWait(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ WaitingCallback* waiting_callback = NULL;
+
+ if (!args.GetNext(&waiting_callback))
+ return args.ThrowError();
+
+ if (!waiting_callback->wait_id())
+ return;
+ BindingsSupport::Get()->CancelWait(waiting_callback->wait_id());
+ waiting_callback->set_wait_id(NULL);
+}
+
+gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
+
+} // namespace
+
+const char Support::kModuleName[] = "mojo/public/bindings/js/support";
+
+v8::Local<v8::ObjectTemplate> Support::GetTemplate(v8::Isolate* isolate) {
+ gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
+ v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
+ &g_wrapper_info);
+
+ if (templ.IsEmpty()) {
+ WaitingCallback::EnsureRegistered(isolate);
+
+ templ = v8::ObjectTemplate::New();
+
+ templ->Set(gin::StringToSymbol(isolate, "asyncWait"),
+ v8::FunctionTemplate::New(AsyncWait));
+ templ->Set(gin::StringToSymbol(isolate, "cancelWait"),
+ v8::FunctionTemplate::New(CancelWait));
+
+ data->SetObjectTemplate(&g_wrapper_info, templ);
+ }
+
+ return templ;
+}
+
+} // namespace js
+} // namespace mojo
diff --git a/mojo/public/bindings/js/support.h b/mojo/public/bindings/js/support.h
new file mode 100644
index 0000000..e5736592
--- /dev/null
+++ b/mojo/public/bindings/js/support.h
@@ -0,0 +1,22 @@
+// 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 MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_
+#define MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_
+
+#include "v8/include/v8.h"
+
+namespace mojo {
+namespace js {
+
+class Support {
+ public:
+ static const char kModuleName[];
+ static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate);
+};
+
+} // namespace js
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_
diff --git a/mojo/public/bindings/js/waiting_callback.cc b/mojo/public/bindings/js/waiting_callback.cc
new file mode 100644
index 0000000..d2613fa
--- /dev/null
+++ b/mojo/public/bindings/js/waiting_callback.cc
@@ -0,0 +1,72 @@
+// 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 "mojo/public/bindings/js/waiting_callback.h"
+
+#include "gin/per_context_data.h"
+#include "gin/per_isolate_data.h"
+
+namespace mojo {
+namespace js {
+
+namespace {
+
+v8::Handle<v8::String> GetHiddenPropertyName(v8::Isolate* isolate) {
+ return gin::StringToSymbol(isolate, "::mojo::js::WaitingCallback");
+}
+
+} // namespace
+
+WaitingCallback::WaitingCallback(v8::Isolate* isolate,
+ v8::Handle<v8::Function> callback)
+ : wait_id_() {
+ v8::Handle<v8::Context> context = isolate->GetCurrentContext();
+ runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
+ GetWrapper(isolate)->SetHiddenValue(GetHiddenPropertyName(isolate), callback);
+}
+
+WaitingCallback::~WaitingCallback() {
+ DCHECK(!wait_id_) << "Waiting callback was destroyed before being cancelled.";
+}
+
+scoped_refptr<WaitingCallback> WaitingCallback::Create(
+ v8::Isolate* isolate, v8::Handle<v8::Function> callback) {
+ return make_scoped_refptr(new WaitingCallback(isolate, callback));
+}
+
+gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin };
+
+gin::WrapperInfo* WaitingCallback::GetWrapperInfo() {
+ return &kWrapperInfo;
+}
+
+void WaitingCallback::EnsureRegistered(v8::Isolate* isolate) {
+ gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
+ if (!data->GetObjectTemplate(&kWrapperInfo).IsEmpty())
+ return;
+ v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
+ templ->SetInternalFieldCount(gin::kNumberOfInternalFields);
+ data->SetObjectTemplate(&kWrapperInfo, templ);
+}
+
+void WaitingCallback::OnHandleReady(MojoResult result) {
+ wait_id_ = NULL;
+
+ if (!runner_)
+ return;
+
+ gin::Runner::Scope scope(runner_.get());
+ v8::Isolate* isolate = runner_->isolate();
+
+ v8::Handle<v8::Value> hidden_value =
+ GetWrapper(isolate)->GetHiddenValue(GetHiddenPropertyName(isolate));
+ v8::Handle<v8::Function> callback;
+ CHECK(gin::ConvertFromV8(hidden_value, &callback));
+
+ v8::Handle<v8::Value> args[] = { gin::ConvertToV8(isolate, result) };
+ runner_->Call(callback, runner_->global(), 1, args);
+}
+
+} // namespace js
+} // namespace mojo
diff --git a/mojo/public/bindings/js/waiting_callback.h b/mojo/public/bindings/js/waiting_callback.h
new file mode 100644
index 0000000..4a5e3e4
--- /dev/null
+++ b/mojo/public/bindings/js/waiting_callback.h
@@ -0,0 +1,56 @@
+// 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 MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_
+#define MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_
+
+#include "gin/runner.h"
+#include "gin/wrappable.h"
+#include "mojo/public/bindings/lib/bindings_support.h"
+
+namespace mojo {
+namespace js {
+
+class WaitingCallback : public gin::Wrappable,
+ public BindingsSupport::AsyncWaitCallback {
+ public:
+ static scoped_refptr<WaitingCallback> Create(
+ v8::Isolate* isolate, v8::Handle<v8::Function> callback);
+
+ static gin::WrapperInfo kWrapperInfo;
+ virtual gin::WrapperInfo* GetWrapperInfo() OVERRIDE;
+ static void EnsureRegistered(v8::Isolate* isolate);
+
+ BindingsSupport::AsyncWaitID wait_id() const {
+ return wait_id_;
+ }
+
+ void set_wait_id(BindingsSupport::AsyncWaitID wait_id) {
+ wait_id_ = wait_id;
+ }
+
+ private:
+ WaitingCallback(v8::Isolate* isolate, v8::Handle<v8::Function> callback);
+ virtual ~WaitingCallback();
+
+ virtual void OnHandleReady(MojoResult result) OVERRIDE;
+
+ base::WeakPtr<gin::Runner> runner_;
+ BindingsSupport::AsyncWaitID wait_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
+};
+
+} // namespace js
+} // namespace mojo
+
+namespace gin {
+
+template<>
+struct Converter<mojo::js::WaitingCallback*>
+ : public WrappableConverter<mojo::js::WaitingCallback> {};
+
+} // namespace gin
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_