• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "node_errors.h"
2 #include "util-inl.h"
3 #include "base_object-inl.h"
4 
5 namespace node {
6 namespace util {
7 
8 using v8::ALL_PROPERTIES;
9 using v8::Array;
10 using v8::ArrayBufferView;
11 using v8::BigInt;
12 using v8::Boolean;
13 using v8::Context;
14 using v8::External;
15 using v8::FunctionCallbackInfo;
16 using v8::FunctionTemplate;
17 using v8::Global;
18 using v8::IndexFilter;
19 using v8::Integer;
20 using v8::Isolate;
21 using v8::KeyCollectionMode;
22 using v8::Local;
23 using v8::Object;
24 using v8::ONLY_CONFIGURABLE;
25 using v8::ONLY_ENUMERABLE;
26 using v8::ONLY_WRITABLE;
27 using v8::Private;
28 using v8::Promise;
29 using v8::PropertyFilter;
30 using v8::Proxy;
31 using v8::SKIP_STRINGS;
32 using v8::SKIP_SYMBOLS;
33 using v8::String;
34 using v8::Uint32;
35 using v8::Value;
36 
GetOwnNonIndexProperties(const FunctionCallbackInfo<Value> & args)37 static void GetOwnNonIndexProperties(
38     const FunctionCallbackInfo<Value>& args) {
39   Environment* env = Environment::GetCurrent(args);
40   Local<Context> context = env->context();
41 
42   CHECK(args[0]->IsObject());
43   CHECK(args[1]->IsUint32());
44 
45   Local<Object> object = args[0].As<Object>();
46 
47   Local<Array> properties;
48 
49   PropertyFilter filter =
50     static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
51 
52   if (!object->GetPropertyNames(
53         context, KeyCollectionMode::kOwnOnly,
54         filter,
55         IndexFilter::kSkipIndices)
56           .ToLocal(&properties)) {
57     return;
58   }
59   args.GetReturnValue().Set(properties);
60 }
61 
GetConstructorName(const FunctionCallbackInfo<Value> & args)62 static void GetConstructorName(
63     const FunctionCallbackInfo<Value>& args) {
64   CHECK(args[0]->IsObject());
65 
66   Local<Object> object = args[0].As<Object>();
67   Local<String> name = object->GetConstructorName();
68 
69   args.GetReturnValue().Set(name);
70 }
71 
GetExternalValue(const FunctionCallbackInfo<Value> & args)72 static void GetExternalValue(
73     const FunctionCallbackInfo<Value>& args) {
74   CHECK(args[0]->IsExternal());
75   Isolate* isolate = args.GetIsolate();
76   Local<External> external = args[0].As<External>();
77 
78   void* ptr = external->Value();
79   uint64_t value = reinterpret_cast<uint64_t>(ptr);
80   Local<BigInt> ret = BigInt::NewFromUnsigned(isolate, value);
81   args.GetReturnValue().Set(ret);
82 }
83 
GetPromiseDetails(const FunctionCallbackInfo<Value> & args)84 static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
85   // Return undefined if it's not a Promise.
86   if (!args[0]->IsPromise())
87     return;
88 
89   auto isolate = args.GetIsolate();
90 
91   Local<Promise> promise = args[0].As<Promise>();
92 
93   int state = promise->State();
94   Local<Value> values[2] = { Integer::New(isolate, state) };
95   size_t number_of_values = 1;
96   if (state != Promise::PromiseState::kPending)
97     values[number_of_values++] = promise->Result();
98   Local<Array> ret = Array::New(isolate, values, number_of_values);
99   args.GetReturnValue().Set(ret);
100 }
101 
GetProxyDetails(const FunctionCallbackInfo<Value> & args)102 static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
103   // Return undefined if it's not a proxy.
104   if (!args[0]->IsProxy())
105     return;
106 
107   Local<Proxy> proxy = args[0].As<Proxy>();
108 
109   // TODO(BridgeAR): Remove the length check as soon as we prohibit access to
110   // the util binding layer. It's accessed in the wild and `esm` would break in
111   // case the check is removed.
112   if (args.Length() == 1 || args[1]->IsTrue()) {
113     Local<Value> ret[] = {
114       proxy->GetTarget(),
115       proxy->GetHandler()
116     };
117 
118     args.GetReturnValue().Set(
119         Array::New(args.GetIsolate(), ret, arraysize(ret)));
120   } else {
121     Local<Value> ret = proxy->GetTarget();
122 
123     args.GetReturnValue().Set(ret);
124   }
125 }
126 
PreviewEntries(const FunctionCallbackInfo<Value> & args)127 static void PreviewEntries(const FunctionCallbackInfo<Value>& args) {
128   if (!args[0]->IsObject())
129     return;
130 
131   Environment* env = Environment::GetCurrent(args);
132   bool is_key_value;
133   Local<Array> entries;
134   if (!args[0].As<Object>()->PreviewEntries(&is_key_value).ToLocal(&entries))
135     return;
136   // Fast path for WeakMap and WeakSet.
137   if (args.Length() == 1)
138     return args.GetReturnValue().Set(entries);
139 
140   Local<Value> ret[] = {
141     entries,
142     Boolean::New(env->isolate(), is_key_value)
143   };
144   return args.GetReturnValue().Set(
145       Array::New(env->isolate(), ret, arraysize(ret)));
146 }
147 
IndexToPrivateSymbol(Environment * env,uint32_t index)148 inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
149 #define V(name, _) &Environment::name,
150   static Local<Private> (Environment::*const methods[])() const = {
151     PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
152   };
153 #undef V
154   CHECK_LT(index, arraysize(methods));
155   return (env->*methods[index])();
156 }
157 
GetHiddenValue(const FunctionCallbackInfo<Value> & args)158 static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
159   Environment* env = Environment::GetCurrent(args);
160 
161   CHECK(args[0]->IsObject());
162   CHECK(args[1]->IsUint32());
163 
164   Local<Object> obj = args[0].As<Object>();
165   uint32_t index = args[1].As<Uint32>()->Value();
166   Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
167   Local<Value> ret;
168   if (obj->GetPrivate(env->context(), private_symbol).ToLocal(&ret))
169     args.GetReturnValue().Set(ret);
170 }
171 
SetHiddenValue(const FunctionCallbackInfo<Value> & args)172 static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) {
173   Environment* env = Environment::GetCurrent(args);
174 
175   CHECK(args[0]->IsObject());
176   CHECK(args[1]->IsUint32());
177 
178   Local<Object> obj = args[0].As<Object>();
179   uint32_t index = args[1].As<Uint32>()->Value();
180   Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
181   bool ret;
182   if (obj->SetPrivate(env->context(), private_symbol, args[2]).To(&ret))
183     args.GetReturnValue().Set(ret);
184 }
185 
Sleep(const FunctionCallbackInfo<Value> & args)186 static void Sleep(const FunctionCallbackInfo<Value>& args) {
187   CHECK(args[0]->IsUint32());
188   uint32_t msec = args[0].As<Uint32>()->Value();
189   uv_sleep(msec);
190 }
191 
ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value> & args)192 void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
193   CHECK(args[0]->IsArrayBufferView());
194   args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
195 }
196 
197 class WeakReference : public BaseObject {
198  public:
WeakReference(Environment * env,Local<Object> object,Local<Object> target)199   WeakReference(Environment* env, Local<Object> object, Local<Object> target)
200     : BaseObject(env, object) {
201     MakeWeak();
202     target_.Reset(env->isolate(), target);
203     target_.SetWeak();
204   }
205 
New(const FunctionCallbackInfo<Value> & args)206   static void New(const FunctionCallbackInfo<Value>& args) {
207     Environment* env = Environment::GetCurrent(args);
208     CHECK(args.IsConstructCall());
209     CHECK(args[0]->IsObject());
210     new WeakReference(env, args.This(), args[0].As<Object>());
211   }
212 
Get(const FunctionCallbackInfo<Value> & args)213   static void Get(const FunctionCallbackInfo<Value>& args) {
214     WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
215     Isolate* isolate = args.GetIsolate();
216     if (!weak_ref->target_.IsEmpty())
217       args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
218   }
219 
IncRef(const FunctionCallbackInfo<Value> & args)220   static void IncRef(const FunctionCallbackInfo<Value>& args) {
221     WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
222     weak_ref->reference_count_++;
223     if (weak_ref->target_.IsEmpty()) return;
224     if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
225   }
226 
DecRef(const FunctionCallbackInfo<Value> & args)227   static void DecRef(const FunctionCallbackInfo<Value>& args) {
228     WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
229     CHECK_GE(weak_ref->reference_count_, 1);
230     weak_ref->reference_count_--;
231     if (weak_ref->target_.IsEmpty()) return;
232     if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
233   }
234 
235   SET_MEMORY_INFO_NAME(WeakReference)
236   SET_SELF_SIZE(WeakReference)
237   SET_NO_MEMORY_INFO()
238 
239  private:
240   Global<Object> target_;
241   uint64_t reference_count_ = 0;
242 };
243 
GuessHandleType(const FunctionCallbackInfo<Value> & args)244 static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
245   Environment* env = Environment::GetCurrent(args);
246   int fd;
247   if (!args[0]->Int32Value(env->context()).To(&fd)) return;
248   CHECK_GE(fd, 0);
249 
250   uv_handle_type t = uv_guess_handle(fd);
251   const char* type = nullptr;
252 
253   switch (t) {
254     case UV_TCP:
255       type = "TCP";
256       break;
257     case UV_TTY:
258       type = "TTY";
259       break;
260     case UV_UDP:
261       type = "UDP";
262       break;
263     case UV_FILE:
264       type = "FILE";
265       break;
266     case UV_NAMED_PIPE:
267       type = "PIPE";
268       break;
269     case UV_UNKNOWN_HANDLE:
270       type = "UNKNOWN";
271       break;
272     default:
273       ABORT();
274   }
275 
276   args.GetReturnValue().Set(OneByteString(env->isolate(), type));
277 }
278 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)279 void Initialize(Local<Object> target,
280                 Local<Value> unused,
281                 Local<Context> context,
282                 void* priv) {
283   Environment* env = Environment::GetCurrent(context);
284 
285 #define V(name, _)                                                            \
286   target->Set(context,                                                        \
287               FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
288               Integer::NewFromUnsigned(env->isolate(), index++)).Check();
289   {
290     uint32_t index = 0;
291     PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
292   }
293 #undef V
294 
295 #define V(name)                                                               \
296   target->Set(context,                                                        \
297               FIXED_ONE_BYTE_STRING(env->isolate(), #name),                   \
298               Integer::New(env->isolate(), Promise::PromiseState::name))      \
299     .FromJust()
300   V(kPending);
301   V(kFulfilled);
302   V(kRejected);
303 #undef V
304 
305   env->SetMethodNoSideEffect(target, "getHiddenValue", GetHiddenValue);
306   env->SetMethod(target, "setHiddenValue", SetHiddenValue);
307   env->SetMethodNoSideEffect(target, "getPromiseDetails", GetPromiseDetails);
308   env->SetMethodNoSideEffect(target, "getProxyDetails", GetProxyDetails);
309   env->SetMethodNoSideEffect(target, "previewEntries", PreviewEntries);
310   env->SetMethodNoSideEffect(target, "getOwnNonIndexProperties",
311                                      GetOwnNonIndexProperties);
312   env->SetMethodNoSideEffect(target, "getConstructorName", GetConstructorName);
313   env->SetMethodNoSideEffect(target, "getExternalValue", GetExternalValue);
314   env->SetMethod(target, "sleep", Sleep);
315 
316   env->SetMethod(target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
317   Local<Object> constants = Object::New(env->isolate());
318   NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
319   NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
320   NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
321   NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
322   NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
323   NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
324   target->Set(context,
325               FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
326               constants).Check();
327 
328   Local<String> should_abort_on_uncaught_toggle =
329       FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
330   CHECK(target
331             ->Set(env->context(),
332                   should_abort_on_uncaught_toggle,
333                   env->should_abort_on_uncaught_toggle().GetJSArray())
334             .FromJust());
335 
336   Local<FunctionTemplate> weak_ref =
337       env->NewFunctionTemplate(WeakReference::New);
338   weak_ref->InstanceTemplate()->SetInternalFieldCount(
339       WeakReference::kInternalFieldCount);
340   weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
341   env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
342   env->SetProtoMethod(weak_ref, "incRef", WeakReference::IncRef);
343   env->SetProtoMethod(weak_ref, "decRef", WeakReference::DecRef);
344   env->SetConstructorFunction(target, "WeakReference", weak_ref);
345 
346   env->SetMethod(target, "guessHandleType", GuessHandleType);
347 }
348 
349 }  // namespace util
350 }  // namespace node
351 
352 NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
353