blob: 0e9912e6e1771cc37207be71500b9f10f68b0cd0 [file] [log] [blame]
[email protected]58e10452012-02-22 03:34:451// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/renderer/module_system.h"
6
7#include "base/bind.h"
[email protected]58e10452012-02-22 03:34:458
9namespace {
10
[email protected]cc0457712012-03-21 03:56:3811const char* kLazyObjectSource = "lazy_object_source";
12const char* kLazyObjectName = "lazy_object_name";
13const char* kLazyObject = "lazy_object";
14
15v8::Handle<v8::Object> EvaluateLazySource(v8::Handle<v8::Object> object) {
16 v8::HandleScope handle_scope;
17 v8::Handle<v8::Value> source_value =
18 object->GetHiddenValue(v8::String::New(kLazyObjectSource));
19 CHECK(!source_value.IsEmpty());
20 v8::Handle<v8::String> source = v8::Handle<v8::String>::Cast(source_value);
21 v8::Handle<v8::Value> name =
22 object->GetHiddenValue(v8::String::New(kLazyObjectName));
23 CHECK(!name.IsEmpty());
24 CHECK(name->IsString());
25 v8::Handle<v8::Script> script = v8::Script::New(source, name);
26 v8::Handle<v8::Value> result = script->Run();
27 CHECK(result->IsObject());
28 return handle_scope.Close(v8::Handle<v8::Object>::Cast(result));
29}
30
31v8::Handle<v8::Value> LazyObjectGetter(
32 const v8::Local<v8::String> property,
33 const v8::AccessorInfo& info) {
34 v8::HandleScope handle_scope;
35 v8::Handle<v8::Object> object = info.Holder();
36 v8::Handle<v8::String> lazy_object_name = v8::String::New(kLazyObject);
37 v8::Handle<v8::Value> lazy_object_value =
38 object->GetHiddenValue(lazy_object_name);
39 CHECK(lazy_object_value.IsEmpty() || lazy_object_value->IsObject());
40 v8::Handle<v8::Object> lazy_object =
41 v8::Handle<v8::Object>::Cast(lazy_object_value);
42 if (lazy_object.IsEmpty()) {
43 lazy_object = EvaluateLazySource(object);
44 object->SetHiddenValue(lazy_object_name, lazy_object);
45 }
46 return handle_scope.Close(lazy_object->Get(property));
47}
48
[email protected]58e10452012-02-22 03:34:4549} // namespace
50
[email protected]ecde1912012-03-16 06:25:3151ModuleSystem::ModuleSystem(SourceMap* source_map)
52 : source_map_(source_map),
53 natives_enabled_(true) {
54 RouteFunction("require",
55 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
56 RouteFunction("requireNative",
[email protected]58e10452012-02-22 03:34:4557 base::Bind(&ModuleSystem::GetNative, base::Unretained(this)));
[email protected]ecde1912012-03-16 06:25:3158
59 v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
60 global->SetHiddenValue(v8::String::New("modules"), v8::Object::New());
[email protected]58e10452012-02-22 03:34:4561}
62
63ModuleSystem::~ModuleSystem() {
64}
65
66void ModuleSystem::Require(const std::string& module_name) {
[email protected]58e10452012-02-22 03:34:4567 v8::HandleScope handle_scope;
[email protected]ecde1912012-03-16 06:25:3168 RequireForJsInner(v8::String::New(module_name.c_str()));
69}
70
71v8::Handle<v8::Value> ModuleSystem::RequireForJs(const v8::Arguments& args) {
72 v8::HandleScope handle_scope;
73 v8::Handle<v8::String> module_name = args[0]->ToString();
74 return handle_scope.Close(RequireForJsInner(module_name));
75}
76
77v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
78 v8::Handle<v8::String> module_name) {
79 v8::HandleScope handle_scope;
80 v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
81 v8::Handle<v8::Object> modules(v8::Handle<v8::Object>::Cast(
82 global->GetHiddenValue(v8::String::New("modules"))));
83 v8::Handle<v8::Value> exports(modules->Get(module_name));
84 if (!exports->IsUndefined())
85 return handle_scope.Close(exports);
86 v8::Handle<v8::Value> source(GetSource(module_name));
87 if (source->IsUndefined())
88 return handle_scope.Close(v8::Undefined());
89 v8::Handle<v8::String> wrapped_source(WrapSource(
90 v8::Handle<v8::String>::Cast(source)));
91 v8::Handle<v8::Function> func =
92 v8::Handle<v8::Function>::Cast(RunString(wrapped_source, module_name));
93 exports = v8::Object::New();
94 v8::Handle<v8::Object> natives(NewInstance());
95 v8::Handle<v8::Value> args[] = {
96 natives->Get(v8::String::NewSymbol("require")),
97 natives->Get(v8::String::NewSymbol("requireNative")),
98 exports,
[email protected]58e10452012-02-22 03:34:4599 };
[email protected]ecde1912012-03-16 06:25:31100 func->Call(global, 3, args);
101 modules->Set(module_name, exports);
102 return handle_scope.Close(exports);
[email protected]58e10452012-02-22 03:34:45103}
104
105void ModuleSystem::RegisterNativeHandler(const std::string& name,
106 scoped_ptr<NativeHandler> native_handler) {
107 native_handler_map_[name] =
108 linked_ptr<NativeHandler>(native_handler.release());
109}
110
[email protected]ecde1912012-03-16 06:25:31111void ModuleSystem::RunString(const std::string& code, const std::string& name) {
[email protected]9fb990b2012-03-13 02:09:41112 v8::HandleScope handle_scope;
[email protected]ecde1912012-03-16 06:25:31113 RunString(v8::String::New(code.c_str()), v8::String::New(name.c_str()));
[email protected]58e10452012-02-22 03:34:45114}
115
[email protected]cc0457712012-03-21 03:56:38116// static
117v8::Handle<v8::Object> ModuleSystem::CreateLazyObject(
118 const std::string& source_name, v8::Handle<v8::String> source) {
119 v8::HandleScope handle_scope;
120 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
121 object_template->SetNamedPropertyHandler(LazyObjectGetter, NULL);
122 v8::Handle<v8::Object> object = object_template->NewInstance();
123 object->SetHiddenValue(v8::String::New(kLazyObjectSource), source);
124 object->SetHiddenValue(v8::String::New(kLazyObjectName),
125 v8::String::New(source_name.c_str()));
126
127 return handle_scope.Close(object);
128}
[email protected]ecde1912012-03-16 06:25:31129
130v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
131 v8::Handle<v8::String> name) {
[email protected]58e10452012-02-22 03:34:45132 v8::HandleScope handle_scope;
[email protected]ecde1912012-03-16 06:25:31133 return handle_scope.Close(v8::Script::New(code, name)->Run());
[email protected]9e03ce22012-03-13 08:50:05134}
135
[email protected]ecde1912012-03-16 06:25:31136v8::Handle<v8::Value> ModuleSystem::GetSource(
137 v8::Handle<v8::String> source_name) {
[email protected]9e03ce22012-03-13 08:50:05138 v8::HandleScope handle_scope;
[email protected]ecde1912012-03-16 06:25:31139 std::string module_name = *v8::String::AsciiValue(source_name);
140 if (!source_map_->Contains(module_name))
[email protected]58e10452012-02-22 03:34:45141 return v8::Undefined();
[email protected]ecde1912012-03-16 06:25:31142 return handle_scope.Close(source_map_->GetSource(module_name));
[email protected]58e10452012-02-22 03:34:45143}
144
145v8::Handle<v8::Value> ModuleSystem::GetNative(const v8::Arguments& args) {
146 CHECK_EQ(1, args.Length());
[email protected]ecde1912012-03-16 06:25:31147 if (!natives_enabled_)
148 return ThrowException("Natives disabled");
[email protected]58e10452012-02-22 03:34:45149 std::string native_name = *v8::String::AsciiValue(args[0]->ToString());
150 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
151 if (i == native_handler_map_.end())
152 return v8::Undefined();
153 return i->second->NewInstance();
154}
[email protected]ecde1912012-03-16 06:25:31155
156v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
157 v8::HandleScope handle_scope;
158 v8::Handle<v8::String> left =
159 v8::String::New("(function(require, requireNative, exports) {");
160 v8::Handle<v8::String> right = v8::String::New("\n})");
161 return handle_scope.Close(
162 v8::String::Concat(left, v8::String::Concat(source, right)));
163}
164
165v8::Handle<v8::Value> ModuleSystem::ThrowException(const std::string& message) {
166 return v8::ThrowException(v8::String::New(message.c_str()));
167}