1 #include "node_native_module_env.h"
2 #include "env-inl.h"
3
4 namespace node {
5 namespace native_module {
6
7 using v8::Context;
8 using v8::DEFAULT;
9 using v8::Function;
10 using v8::FunctionCallbackInfo;
11 using v8::IntegrityLevel;
12 using v8::Isolate;
13 using v8::Local;
14 using v8::MaybeLocal;
15 using v8::Name;
16 using v8::None;
17 using v8::Object;
18 using v8::PropertyCallbackInfo;
19 using v8::Set;
20 using v8::SideEffectType;
21 using v8::String;
22 using v8::Value;
23
24 // TODO(joyeecheung): make these more general and put them into util.h
ToJsSet(Local<Context> context,const std::set<std::string> & in)25 Local<Set> ToJsSet(Local<Context> context, const std::set<std::string>& in) {
26 Isolate* isolate = context->GetIsolate();
27 Local<Set> out = Set::New(isolate);
28 for (auto const& x : in) {
29 out->Add(context, OneByteString(isolate, x.c_str(), x.size()))
30 .ToLocalChecked();
31 }
32 return out;
33 }
34
Add(const char * id,const UnionBytes & source)35 bool NativeModuleEnv::Add(const char* id, const UnionBytes& source) {
36 return NativeModuleLoader::GetInstance()->Add(id, source);
37 }
38
Exists(const char * id)39 bool NativeModuleEnv::Exists(const char* id) {
40 return NativeModuleLoader::GetInstance()->Exists(id);
41 }
42
GetSourceObject(Local<Context> context)43 Local<Object> NativeModuleEnv::GetSourceObject(Local<Context> context) {
44 return NativeModuleLoader::GetInstance()->GetSourceObject(context);
45 }
46
GetConfigString(Isolate * isolate)47 Local<String> NativeModuleEnv::GetConfigString(Isolate* isolate) {
48 return NativeModuleLoader::GetInstance()->GetConfigString(isolate);
49 }
50
GetModuleCategories(Local<Name> property,const PropertyCallbackInfo<Value> & info)51 void NativeModuleEnv::GetModuleCategories(
52 Local<Name> property, const PropertyCallbackInfo<Value>& info) {
53 Environment* env = Environment::GetCurrent(info);
54 Isolate* isolate = env->isolate();
55 Local<Context> context = env->context();
56 Local<Object> result = Object::New(isolate);
57
58 // Copy from the per-process categories
59 std::set<std::string> cannot_be_required =
60 NativeModuleLoader::GetInstance()->GetCannotBeRequired();
61 std::set<std::string> can_be_required =
62 NativeModuleLoader::GetInstance()->GetCanBeRequired();
63
64 if (!env->owns_process_state()) {
65 can_be_required.erase("trace_events");
66 cannot_be_required.insert("trace_events");
67 }
68
69 result
70 ->Set(context,
71 OneByteString(isolate, "cannotBeRequired"),
72 ToJsSet(context, cannot_be_required))
73 .FromJust();
74 result
75 ->Set(context,
76 OneByteString(isolate, "canBeRequired"),
77 ToJsSet(context, can_be_required))
78 .FromJust();
79 info.GetReturnValue().Set(result);
80 }
81
GetCacheUsage(const FunctionCallbackInfo<Value> & args)82 void NativeModuleEnv::GetCacheUsage(const FunctionCallbackInfo<Value>& args) {
83 Environment* env = Environment::GetCurrent(args);
84 Isolate* isolate = env->isolate();
85 Local<Context> context = env->context();
86 Local<Object> result = Object::New(isolate);
87 result
88 ->Set(env->context(),
89 OneByteString(isolate, "compiledWithCache"),
90 ToJsSet(context, env->native_modules_with_cache))
91 .FromJust();
92 result
93 ->Set(env->context(),
94 OneByteString(isolate, "compiledWithoutCache"),
95 ToJsSet(context, env->native_modules_without_cache))
96 .FromJust();
97 args.GetReturnValue().Set(result);
98 }
99
ModuleIdsGetter(Local<Name> property,const PropertyCallbackInfo<Value> & info)100 void NativeModuleEnv::ModuleIdsGetter(Local<Name> property,
101 const PropertyCallbackInfo<Value>& info) {
102 Isolate* isolate = info.GetIsolate();
103
104 std::vector<std::string> ids =
105 NativeModuleLoader::GetInstance()->GetModuleIds();
106 info.GetReturnValue().Set(
107 ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked());
108 }
109
ConfigStringGetter(Local<Name> property,const PropertyCallbackInfo<Value> & info)110 void NativeModuleEnv::ConfigStringGetter(
111 Local<Name> property, const PropertyCallbackInfo<Value>& info) {
112 info.GetReturnValue().Set(GetConfigString(info.GetIsolate()));
113 }
114
RecordResult(const char * id,NativeModuleLoader::Result result,Environment * env)115 void NativeModuleEnv::RecordResult(const char* id,
116 NativeModuleLoader::Result result,
117 Environment* env) {
118 if (result == NativeModuleLoader::Result::kWithCache) {
119 env->native_modules_with_cache.insert(id);
120 } else {
121 env->native_modules_without_cache.insert(id);
122 }
123 }
CompileFunction(const FunctionCallbackInfo<Value> & args)124 void NativeModuleEnv::CompileFunction(const FunctionCallbackInfo<Value>& args) {
125 Environment* env = Environment::GetCurrent(args);
126 CHECK(args[0]->IsString());
127 node::Utf8Value id_v(env->isolate(), args[0].As<String>());
128 const char* id = *id_v;
129 NativeModuleLoader::Result result;
130 MaybeLocal<Function> maybe =
131 NativeModuleLoader::GetInstance()->CompileAsModule(
132 env->context(), id, &result);
133 RecordResult(id, result, env);
134 Local<Function> fn;
135 if (maybe.ToLocal(&fn)) {
136 args.GetReturnValue().Set(fn);
137 }
138 }
139
140 // Returns Local<Function> of the compiled module if return_code_cache
141 // is false (we are only compiling the function).
142 // Otherwise return a Local<Object> containing the cache.
LookupAndCompile(Local<Context> context,const char * id,std::vector<Local<String>> * parameters,Environment * optional_env)143 MaybeLocal<Function> NativeModuleEnv::LookupAndCompile(
144 Local<Context> context,
145 const char* id,
146 std::vector<Local<String>>* parameters,
147 Environment* optional_env) {
148 NativeModuleLoader::Result result;
149 MaybeLocal<Function> maybe =
150 NativeModuleLoader::GetInstance()->LookupAndCompile(
151 context, id, parameters, &result);
152 if (optional_env != nullptr) {
153 RecordResult(id, result, optional_env);
154 }
155 return maybe;
156 }
157
158 // TODO(joyeecheung): It is somewhat confusing that Class::Initialize
159 // is used to initialize to the binding, but it is the current convention.
160 // Rename this across the code base to something that makes more sense.
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)161 void NativeModuleEnv::Initialize(Local<Object> target,
162 Local<Value> unused,
163 Local<Context> context,
164 void* priv) {
165 Environment* env = Environment::GetCurrent(context);
166
167 target
168 ->SetAccessor(env->context(),
169 env->config_string(),
170 ConfigStringGetter,
171 nullptr,
172 MaybeLocal<Value>(),
173 DEFAULT,
174 None,
175 SideEffectType::kHasNoSideEffect)
176 .Check();
177 target
178 ->SetAccessor(env->context(),
179 FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"),
180 ModuleIdsGetter,
181 nullptr,
182 MaybeLocal<Value>(),
183 DEFAULT,
184 None,
185 SideEffectType::kHasNoSideEffect)
186 .Check();
187
188 target
189 ->SetAccessor(env->context(),
190 FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"),
191 GetModuleCategories,
192 nullptr,
193 Local<Value>(),
194 DEFAULT,
195 None,
196 SideEffectType::kHasNoSideEffect)
197 .Check();
198
199 env->SetMethod(target, "getCacheUsage", NativeModuleEnv::GetCacheUsage);
200 env->SetMethod(target, "compileFunction", NativeModuleEnv::CompileFunction);
201 // internalBinding('native_module') should be frozen
202 target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
203 }
204
205 } // namespace native_module
206 } // namespace node
207
208 NODE_MODULE_CONTEXT_AWARE_INTERNAL(
209 native_module, node::native_module::NativeModuleEnv::Initialize)
210