Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_serdes.cc
Go to the documentation of this file.
1 #include "node.h"
2 #include "node_buffer.h"
3 #include "base-object.h"
4 #include "base-object-inl.h"
5 #include "env.h"
6 #include "env-inl.h"
7 #include "v8.h"
8 
9 namespace node {
10 
11 using v8::Array;
12 using v8::ArrayBuffer;
13 using v8::Context;
14 using v8::Function;
15 using v8::FunctionCallbackInfo;
16 using v8::FunctionTemplate;
17 using v8::Integer;
18 using v8::Isolate;
19 using v8::Just;
20 using v8::Local;
21 using v8::Maybe;
22 using v8::MaybeLocal;
23 using v8::Nothing;
24 using v8::Object;
25 using v8::SharedArrayBuffer;
26 using v8::String;
27 using v8::Value;
28 using v8::ValueDeserializer;
29 using v8::ValueSerializer;
30 
31 namespace {
32 
33 class SerializerContext : public BaseObject,
34  public ValueSerializer::Delegate {
35  public:
36  SerializerContext(Environment* env,
37  Local<Object> wrap);
38 
39  ~SerializerContext() {}
40 
41  void ThrowDataCloneError(Local<String> message) override;
42  Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override;
43  Maybe<uint32_t> GetSharedArrayBufferId(
44  Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override;
45 
46  static void SetTreatArrayBufferViewsAsHostObjects(
47  const FunctionCallbackInfo<Value>& args);
48 
49  static void New(const FunctionCallbackInfo<Value>& args);
50  static void WriteHeader(const FunctionCallbackInfo<Value>& args);
51  static void WriteValue(const FunctionCallbackInfo<Value>& args);
52  static void ReleaseBuffer(const FunctionCallbackInfo<Value>& args);
53  static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args);
54  static void WriteUint32(const FunctionCallbackInfo<Value>& args);
55  static void WriteUint64(const FunctionCallbackInfo<Value>& args);
56  static void WriteDouble(const FunctionCallbackInfo<Value>& args);
57  static void WriteRawBytes(const FunctionCallbackInfo<Value>& args);
58  private:
59  ValueSerializer serializer_;
60 };
61 
62 class DeserializerContext : public BaseObject,
63  public ValueDeserializer::Delegate {
64  public:
65  DeserializerContext(Environment* env,
66  Local<Object> wrap,
67  Local<Value> buffer);
68 
69  ~DeserializerContext() {}
70 
71  MaybeLocal<Object> ReadHostObject(Isolate* isolate) override;
72 
73  static void New(const FunctionCallbackInfo<Value>& args);
74  static void ReadHeader(const FunctionCallbackInfo<Value>& args);
75  static void ReadValue(const FunctionCallbackInfo<Value>& args);
76  static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args);
77  static void GetWireFormatVersion(const FunctionCallbackInfo<Value>& args);
78  static void ReadUint32(const FunctionCallbackInfo<Value>& args);
79  static void ReadUint64(const FunctionCallbackInfo<Value>& args);
80  static void ReadDouble(const FunctionCallbackInfo<Value>& args);
81  static void ReadRawBytes(const FunctionCallbackInfo<Value>& args);
82  private:
83  const uint8_t* data_;
84  const size_t length_;
85 
86  ValueDeserializer deserializer_;
87 };
88 
89 SerializerContext::SerializerContext(Environment* env, Local<Object> wrap)
90  : BaseObject(env, wrap),
91  serializer_(env->isolate(), this) {
92  MakeWeak<SerializerContext>(this);
93 }
94 
95 void SerializerContext::ThrowDataCloneError(Local<String> message) {
96  Local<Value> args[1] = { message };
97  Local<Value> get_data_clone_error =
98  object()->Get(env()->context(),
99  env()->get_data_clone_error_string())
100  .ToLocalChecked();
101 
102  CHECK(get_data_clone_error->IsFunction());
103  MaybeLocal<Value> error =
104  get_data_clone_error.As<Function>()->Call(env()->context(),
105  object(),
106  arraysize(args),
107  args);
108 
109  if (error.IsEmpty()) return;
110 
111  env()->isolate()->ThrowException(error.ToLocalChecked());
112 }
113 
114 Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId(
115  Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) {
116  Local<Value> args[1] = { shared_array_buffer };
117  Local<Value> get_shared_array_buffer_id =
118  object()->Get(env()->context(),
119  env()->get_shared_array_buffer_id_string())
120  .ToLocalChecked();
121 
122  if (!get_shared_array_buffer_id->IsFunction()) {
123  return ValueSerializer::Delegate::GetSharedArrayBufferId(
124  isolate, shared_array_buffer);
125  }
126 
127  MaybeLocal<Value> id =
128  get_shared_array_buffer_id.As<Function>()->Call(env()->context(),
129  object(),
130  arraysize(args),
131  args);
132 
133  if (id.IsEmpty()) return Nothing<uint32_t>();
134 
135  return id.ToLocalChecked()->Uint32Value(env()->context());
136 }
137 
138 Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate,
139  Local<Object> input) {
140  MaybeLocal<Value> ret;
141  Local<Value> args[1] = { input };
142 
143  Local<Value> write_host_object =
144  object()->Get(env()->context(),
145  env()->write_host_object_string()).ToLocalChecked();
146 
147  if (!write_host_object->IsFunction()) {
148  return ValueSerializer::Delegate::WriteHostObject(isolate, input);
149  }
150 
151  ret = write_host_object.As<Function>()->Call(env()->context(),
152  object(),
153  arraysize(args),
154  args);
155 
156  if (ret.IsEmpty())
157  return Nothing<bool>();
158 
159  return Just(true);
160 }
161 
162 void SerializerContext::New(const FunctionCallbackInfo<Value>& args) {
163  Environment* env = Environment::GetCurrent(args);
164 
165  new SerializerContext(env, args.This());
166 }
167 
168 void SerializerContext::WriteHeader(const FunctionCallbackInfo<Value>& args) {
169  SerializerContext* ctx;
170  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
171  ctx->serializer_.WriteHeader();
172 }
173 
174 void SerializerContext::WriteValue(const FunctionCallbackInfo<Value>& args) {
175  SerializerContext* ctx;
176  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
177  Maybe<bool> ret =
178  ctx->serializer_.WriteValue(ctx->env()->context(), args[0]);
179 
180  if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
181 }
182 
183 void SerializerContext::SetTreatArrayBufferViewsAsHostObjects(
184  const FunctionCallbackInfo<Value>& args) {
185  SerializerContext* ctx;
186  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
187 
188  Maybe<bool> value = args[0]->BooleanValue(ctx->env()->context());
189  if (value.IsNothing()) return;
190  ctx->serializer_.SetTreatArrayBufferViewsAsHostObjects(value.FromJust());
191 }
192 
193 void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) {
194  SerializerContext* ctx;
195  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
196 
197  std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
198  auto buf = Buffer::New(ctx->env(),
199  reinterpret_cast<char*>(ret.first),
200  ret.second);
201 
202  if (!buf.IsEmpty()) {
203  args.GetReturnValue().Set(buf.ToLocalChecked());
204  }
205 }
206 
207 void SerializerContext::TransferArrayBuffer(
208  const FunctionCallbackInfo<Value>& args) {
209  SerializerContext* ctx;
210  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
211 
212  Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
213  if (id.IsNothing()) return;
214 
215  if (!args[1]->IsArrayBuffer())
216  return ctx->env()->ThrowTypeError("arrayBuffer must be an ArrayBuffer");
217 
218  Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
219  ctx->serializer_.TransferArrayBuffer(id.FromJust(), ab);
220  return;
221 }
222 
223 void SerializerContext::WriteUint32(const FunctionCallbackInfo<Value>& args) {
224  SerializerContext* ctx;
225  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
226 
227  Maybe<uint32_t> value = args[0]->Uint32Value(ctx->env()->context());
228  if (value.IsNothing()) return;
229 
230  ctx->serializer_.WriteUint32(value.FromJust());
231 }
232 
233 void SerializerContext::WriteUint64(const FunctionCallbackInfo<Value>& args) {
234  SerializerContext* ctx;
235  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
236 
237  Maybe<uint32_t> arg0 = args[0]->Uint32Value(ctx->env()->context());
238  Maybe<uint32_t> arg1 = args[1]->Uint32Value(ctx->env()->context());
239  if (arg0.IsNothing() || arg1.IsNothing())
240  return;
241 
242  uint64_t hi = arg0.FromJust();
243  uint64_t lo = arg1.FromJust();
244  ctx->serializer_.WriteUint64((hi << 32) | lo);
245 }
246 
247 void SerializerContext::WriteDouble(const FunctionCallbackInfo<Value>& args) {
248  SerializerContext* ctx;
249  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
250 
251  Maybe<double> value = args[0]->NumberValue(ctx->env()->context());
252  if (value.IsNothing()) return;
253 
254  ctx->serializer_.WriteDouble(value.FromJust());
255 }
256 
257 void SerializerContext::WriteRawBytes(const FunctionCallbackInfo<Value>& args) {
258  SerializerContext* ctx;
259  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
260 
261  if (!args[0]->IsUint8Array()) {
262  return ctx->env()->ThrowTypeError("source must be a Uint8Array");
263  }
264 
265  ctx->serializer_.WriteRawBytes(Buffer::Data(args[0]),
266  Buffer::Length(args[0]));
267 }
268 
269 DeserializerContext::DeserializerContext(Environment* env,
270  Local<Object> wrap,
271  Local<Value> buffer)
272  : BaseObject(env, wrap),
273  data_(reinterpret_cast<const uint8_t*>(Buffer::Data(buffer))),
274  length_(Buffer::Length(buffer)),
275  deserializer_(env->isolate(), data_, length_, this) {
276  object()->Set(env->context(), env->buffer_string(), buffer).FromJust();
277 
278  MakeWeak<DeserializerContext>(this);
279 }
280 
281 MaybeLocal<Object> DeserializerContext::ReadHostObject(Isolate* isolate) {
282  Local<Value> read_host_object =
283  object()->Get(env()->context(),
284  env()->read_host_object_string()).ToLocalChecked();
285 
286  if (!read_host_object->IsFunction()) {
287  return ValueDeserializer::Delegate::ReadHostObject(isolate);
288  }
289 
290  MaybeLocal<Value> ret =
291  read_host_object.As<Function>()->Call(env()->context(),
292  object(),
293  0,
294  nullptr);
295 
296  if (ret.IsEmpty())
297  return MaybeLocal<Object>();
298 
299  Local<Value> return_value = ret.ToLocalChecked();
300  if (!return_value->IsObject()) {
301  env()->ThrowTypeError("readHostObject must return an object");
302  return MaybeLocal<Object>();
303  }
304 
305  return return_value.As<Object>();
306 }
307 
308 void DeserializerContext::New(const FunctionCallbackInfo<Value>& args) {
309  Environment* env = Environment::GetCurrent(args);
310 
311  if (!args[0]->IsUint8Array()) {
312  return env->ThrowTypeError("buffer must be a Uint8Array");
313  }
314 
315  new DeserializerContext(env, args.This(), args[0]);
316 }
317 
318 void DeserializerContext::ReadHeader(const FunctionCallbackInfo<Value>& args) {
319  DeserializerContext* ctx;
320  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
321 
322  Maybe<bool> ret = ctx->deserializer_.ReadHeader(ctx->env()->context());
323 
324  if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
325 }
326 
327 void DeserializerContext::ReadValue(const FunctionCallbackInfo<Value>& args) {
328  DeserializerContext* ctx;
329  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
330 
331  MaybeLocal<Value> ret = ctx->deserializer_.ReadValue(ctx->env()->context());
332 
333  if (!ret.IsEmpty()) args.GetReturnValue().Set(ret.ToLocalChecked());
334 }
335 
336 void DeserializerContext::TransferArrayBuffer(
337  const FunctionCallbackInfo<Value>& args) {
338  DeserializerContext* ctx;
339  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
340 
341  Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
342  if (id.IsNothing()) return;
343 
344  if (args[1]->IsArrayBuffer()) {
345  Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
346  ctx->deserializer_.TransferArrayBuffer(id.FromJust(), ab);
347  return;
348  }
349 
350  if (args[1]->IsSharedArrayBuffer()) {
351  Local<SharedArrayBuffer> sab = args[1].As<SharedArrayBuffer>();
352  ctx->deserializer_.TransferSharedArrayBuffer(id.FromJust(), sab);
353  return;
354  }
355 
356  return ctx->env()->ThrowTypeError("arrayBuffer must be an ArrayBuffer or "
357  "SharedArrayBuffer");
358 }
359 
360 void DeserializerContext::GetWireFormatVersion(
361  const FunctionCallbackInfo<Value>& args) {
362  DeserializerContext* ctx;
363  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
364 
365  args.GetReturnValue().Set(ctx->deserializer_.GetWireFormatVersion());
366 }
367 
368 void DeserializerContext::ReadUint32(const FunctionCallbackInfo<Value>& args) {
369  DeserializerContext* ctx;
370  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
371 
372  uint32_t value;
373  bool ok = ctx->deserializer_.ReadUint32(&value);
374  if (!ok) return ctx->env()->ThrowError("ReadUint32() failed");
375  return args.GetReturnValue().Set(value);
376 }
377 
378 void DeserializerContext::ReadUint64(const FunctionCallbackInfo<Value>& args) {
379  DeserializerContext* ctx;
380  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
381 
382  uint64_t value;
383  bool ok = ctx->deserializer_.ReadUint64(&value);
384  if (!ok) return ctx->env()->ThrowError("ReadUint64() failed");
385 
386  uint32_t hi = static_cast<uint32_t>(value >> 32);
387  uint32_t lo = static_cast<uint32_t>(value);
388 
389  Isolate* isolate = ctx->env()->isolate();
390  Local<Context> context = ctx->env()->context();
391 
392  Local<Array> ret = Array::New(isolate, 2);
393  ret->Set(context, 0, Integer::NewFromUnsigned(isolate, hi)).FromJust();
394  ret->Set(context, 1, Integer::NewFromUnsigned(isolate, lo)).FromJust();
395  return args.GetReturnValue().Set(ret);
396 }
397 
398 void DeserializerContext::ReadDouble(const FunctionCallbackInfo<Value>& args) {
399  DeserializerContext* ctx;
400  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
401 
402  double value;
403  bool ok = ctx->deserializer_.ReadDouble(&value);
404  if (!ok) return ctx->env()->ThrowError("ReadDouble() failed");
405  return args.GetReturnValue().Set(value);
406 }
407 
408 void DeserializerContext::ReadRawBytes(
409  const FunctionCallbackInfo<Value>& args) {
410  DeserializerContext* ctx;
411  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
412 
413  Maybe<int64_t> length_arg = args[0]->IntegerValue(ctx->env()->context());
414  if (length_arg.IsNothing()) return;
415  size_t length = length_arg.FromJust();
416 
417  const void* data;
418  bool ok = ctx->deserializer_.ReadRawBytes(length, &data);
419  if (!ok) return ctx->env()->ThrowError("ReadRawBytes() failed");
420 
421  const uint8_t* position = reinterpret_cast<const uint8_t*>(data);
422  CHECK_GE(position, ctx->data_);
423  CHECK_LE(position + length, ctx->data_ + ctx->length_);
424 
425  const uint32_t offset = position - ctx->data_;
426  CHECK_EQ(ctx->data_ + offset, position);
427 
428  args.GetReturnValue().Set(offset);
429 }
430 
431 void InitializeSerdesBindings(Local<Object> target,
432  Local<Value> unused,
433  Local<Context> context) {
434  Environment* env = Environment::GetCurrent(context);
435  Local<FunctionTemplate> ser =
436  env->NewFunctionTemplate(SerializerContext::New);
437 
438  ser->InstanceTemplate()->SetInternalFieldCount(1);
439 
440  env->SetProtoMethod(ser, "writeHeader", SerializerContext::WriteHeader);
441  env->SetProtoMethod(ser, "writeValue", SerializerContext::WriteValue);
442  env->SetProtoMethod(ser, "releaseBuffer", SerializerContext::ReleaseBuffer);
443  env->SetProtoMethod(ser,
444  "transferArrayBuffer",
445  SerializerContext::TransferArrayBuffer);
446  env->SetProtoMethod(ser, "writeUint32", SerializerContext::WriteUint32);
447  env->SetProtoMethod(ser, "writeUint64", SerializerContext::WriteUint64);
448  env->SetProtoMethod(ser, "writeDouble", SerializerContext::WriteDouble);
449  env->SetProtoMethod(ser, "writeRawBytes", SerializerContext::WriteRawBytes);
450  env->SetProtoMethod(ser,
451  "_setTreatArrayBufferViewsAsHostObjects",
452  SerializerContext::SetTreatArrayBufferViewsAsHostObjects);
453 
454  Local<String> serializerString =
455  FIXED_ONE_BYTE_STRING(env->isolate(), "Serializer");
456  ser->SetClassName(serializerString);
457  target->Set(env->context(),
458  serializerString,
459  ser->GetFunction(env->context()).ToLocalChecked()).FromJust();
460 
461  Local<FunctionTemplate> des =
462  env->NewFunctionTemplate(DeserializerContext::New);
463 
464  des->InstanceTemplate()->SetInternalFieldCount(1);
465 
466  env->SetProtoMethod(des, "readHeader", DeserializerContext::ReadHeader);
467  env->SetProtoMethod(des, "readValue", DeserializerContext::ReadValue);
468  env->SetProtoMethod(des,
469  "getWireFormatVersion",
470  DeserializerContext::GetWireFormatVersion);
471  env->SetProtoMethod(des,
472  "transferArrayBuffer",
473  DeserializerContext::TransferArrayBuffer);
474  env->SetProtoMethod(des, "readUint32", DeserializerContext::ReadUint32);
475  env->SetProtoMethod(des, "readUint64", DeserializerContext::ReadUint64);
476  env->SetProtoMethod(des, "readDouble", DeserializerContext::ReadDouble);
477  env->SetProtoMethod(des, "_readRawBytes", DeserializerContext::ReadRawBytes);
478 
479  Local<String> deserializerString =
480  FIXED_ONE_BYTE_STRING(env->isolate(), "Deserializer");
481  des->SetClassName(deserializerString);
482  target->Set(env->context(),
483  deserializerString,
484  des->GetFunction(env->context()).ToLocalChecked()).FromJust();
485 }
486 
487 } // anonymous namespace
488 } // namespace node
489 
490 NODE_MODULE_CONTEXT_AWARE_BUILTIN(serdes, node::InitializeSerdesBindings)
unsigned char * buf
Definition: cares_wrap.cc:483
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
QueryWrap * wrap
Definition: cares_wrap.cc:478
union node::cares_wrap::@8::CaresAsyncData::@0 data
size_t Length(Local< Value > val)
Definition: node_buffer.cc:227
this position
Definition: v8ustack.d:383
char * Data(Local< Value > val)
Definition: node_buffer.cc:211
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
this ctx
Definition: v8ustack.d:369