• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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