| Index: gin/modules/module_registry.cc
|
| diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..78a102c0a6da5186e83987ecef41716181d4c8f0
|
| --- /dev/null
|
| +++ b/gin/modules/module_registry.cc
|
| @@ -0,0 +1,188 @@
|
| +// 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_registry.h"
|
| +
|
| +#include <assert.h>
|
| +#include <string>
|
| +#include <vector>
|
| +#include "gin/arguments.h"
|
| +#include "gin/converter.h"
|
| +#include "gin/per_isolate_data.h"
|
| +#include "gin/wrapper_info.h"
|
| +
|
| +using v8::External;
|
| +using v8::Handle;
|
| +using v8::Isolate;
|
| +using v8::ObjectTemplate;
|
| +
|
| +namespace gin {
|
| +
|
| +struct PendingModule {
|
| + PendingModule();
|
| + ~PendingModule();
|
| +
|
| + std::string id;
|
| + std::vector<std::string> dependencies;
|
| + v8::Persistent<v8::Value> factory;
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +void Define(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
| + Arguments args(info);
|
| +
|
| + if (!info.Length())
|
| + return args.ThrowTypeError("At least one argument is required.");
|
| +
|
| + std::string id;
|
| + std::vector<std::string> dependencies;
|
| + Handle<v8::Value> factory;
|
| +
|
| + if (args.PeekNext()->IsString())
|
| + args.GetNext(&id);
|
| + if (args.PeekNext()->IsArray())
|
| + args.GetNext(&dependencies);
|
| + if (!args.GetNext(&factory))
|
| + return args.ThrowError();
|
| +
|
| + PendingModule* pending = new PendingModule;
|
| + pending->id = id;
|
| + pending->dependencies = dependencies;
|
| + pending->factory.Reset(args.isolate(), factory);
|
| +
|
| + ModuleRegistry* registry =
|
| + ModuleRegistry::From(args.isolate()->GetCurrentContext());
|
| + registry->AddPendingModule(args.isolate(), pending);
|
| +}
|
| +
|
| +WrapperInfo g_wrapper_info = {};
|
| +
|
| +v8::Local<v8::FunctionTemplate> GetDefineTemplate(v8::Isolate* isolate) {
|
| + PerIsolateData* data = PerIsolateData::From(isolate);
|
| + v8::Local<v8::FunctionTemplate> templ = data->GetFunctionTemplate(
|
| + &g_wrapper_info);
|
| + if (templ.IsEmpty()) {
|
| + templ = v8::FunctionTemplate::New(Define);
|
| + data->SetFunctionTemplate(&g_wrapper_info, templ);
|
| + }
|
| + return templ;
|
| +}
|
| +
|
| +Handle<v8::String> GetHiddenValueKey(v8::Isolate* isolate) {
|
| + return StringToSymbol(isolate, "::gin::ModuleRegistry");
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +PendingModule::PendingModule() {
|
| +}
|
| +
|
| +PendingModule::~PendingModule() {
|
| + factory.Reset();
|
| +}
|
| +
|
| +ModuleRegistry::ModuleRegistry(v8::Isolate* isolate)
|
| + : modules_(isolate, v8::Object::New()) {
|
| +}
|
| +
|
| +ModuleRegistry::~ModuleRegistry() {
|
| + for (PendingModuleList::iterator it = pending_modules_.begin();
|
| + it != pending_modules_.end(); ++it) {
|
| + delete *it;
|
| + }
|
| + modules_.Reset();
|
| +}
|
| +
|
| +void ModuleRegistry::RegisterGlobals(v8::Isolate* isolate,
|
| + Handle<v8::ObjectTemplate> templ) {
|
| + templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate));
|
| +}
|
| +
|
| +void ModuleRegistry::AddBuiltinModule(Isolate* isolate,
|
| + const std::string& id,
|
| + Handle<ObjectTemplate> templ) {
|
| + assert(!id.empty());
|
| + Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_);
|
| + modules->Set(StringToV8(isolate, id), templ->NewInstance());
|
| +}
|
| +
|
| +ModuleRegistry* ModuleRegistry::From(Handle<v8::Context> context) {
|
| + v8::Isolate* isolate = context->GetIsolate();
|
| + Handle<v8::String> key = GetHiddenValueKey(isolate);
|
| + Handle<v8::Value> value = context->Global()->GetHiddenValue(key);
|
| + Handle<v8::External> external;
|
| + if (value.IsEmpty() || !ConvertFromV8(value, &external)) {
|
| + PerContextData* data = PerContextData::From(context);
|
| + if (!data)
|
| + return NULL;
|
| + ModuleRegistry* registry = new ModuleRegistry(isolate);
|
| + context->Global()->SetHiddenValue(key, v8::External::New(registry));
|
| + data->AddSupplement(registry);
|
| + return registry;
|
| + }
|
| + return static_cast<ModuleRegistry*>(external->Value());
|
| +}
|
| +
|
| +void ModuleRegistry::AddPendingModule(v8::Isolate* isolate,
|
| + PendingModule* pending) {
|
| + if (AttemptToLoad(isolate, pending))
|
| + AttemptToLoadPendingModules(isolate);
|
| +}
|
| +
|
| +void ModuleRegistry::Detach(Handle<v8::Context> context) {
|
| + context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()),
|
| + Handle<v8::Value>());
|
| +}
|
| +
|
| +bool ModuleRegistry::AttemptToLoad(v8::Isolate* isolate,
|
| + PendingModule* pending) {
|
| + Handle<v8::Object> modules = v8::Local<v8::Object>::New(isolate, modules_);
|
| + Handle<v8::String> key = StringToV8(isolate, pending->id);
|
| +
|
| + if (!pending->id.empty() && modules->HasOwnProperty(key)) {
|
| + // We've already loaded a module with this name. Ignore the new one.
|
| + delete pending;
|
| + return true;
|
| + }
|
| +
|
| + size_t argc = pending->dependencies.size();
|
| + std::vector<Handle<v8::Value> > argv(argc);
|
| + for (size_t i = 0; i < argc; ++i) {
|
| + Handle<v8::String> key = StringToV8(isolate, pending->dependencies[i]);
|
| + if (!modules->HasOwnProperty(key)) {
|
| + pending_modules_.push_back(pending);
|
| + return false;
|
| + }
|
| + argv[i] = modules->Get(key);
|
| + }
|
| +
|
| + Handle<v8::Value> module = v8::Local<v8::Value>::New(
|
| + isolate, pending->factory);
|
| +
|
| + Handle<v8::Function> factory;
|
| + if (ConvertFromV8(module, &factory)) {
|
| + v8::Handle<v8::Object> global = isolate->GetCurrentContext()->Global();
|
| + module = factory->Call(global, argc, argv.data());
|
| + // TODO(abarth): What should we do with exceptions?
|
| + }
|
| +
|
| + if (!pending->id.empty() && !module.IsEmpty())
|
| + modules->Set(key, module);
|
| +
|
| + delete pending;
|
| + return true;
|
| +}
|
| +
|
| +void ModuleRegistry::AttemptToLoadPendingModules(v8::Isolate* isolate) {
|
| + PendingModuleList pending_modules;
|
| + pending_modules.swap(pending_modules_);
|
| + for (PendingModuleList::iterator it = pending_modules.begin();
|
| + it != pending_modules.end(); ++it) {
|
| + AttemptToLoad(isolate, *it);
|
| + }
|
| +}
|
| +
|
| +} // namespace gin
|
|
|