@@ -465,15 +465,29 @@ static void ReallyExit(const FunctionCallbackInfo<Value>& args) { |
465 | 465 |
|
466 | 466 | namespace process { |
467 | 467 |
|
468 | | -BindingData::BindingData(Realm* realm, v8::Local<v8::Object> object) |
469 | | - : SnapshotableObject(realm, object, type_int) { |
| 468 | +BindingData::BindingData(Realm* realm, |
| 469 | + v8::Local<v8::Object> object, |
| 470 | + InternalFieldInfo* info) |
| 471 | + : SnapshotableObject(realm, object, type_int), |
| 472 | + hrtime_buffer_(realm->isolate(), |
| 473 | + kHrTimeBufferLength, |
| 474 | + MAYBE_FIELD_PTR(info, hrtime_buffer)) { |
470 | 475 | Isolate* isolate = realm->isolate(); |
471 | 476 | Local<Context> context = realm->context(); |
472 | | - Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, kBufferSize); |
473 | | - array_buffer_.Reset(isolate, ab); |
474 | | - object->Set(context, FIXED_ONE_BYTE_STRING(isolate, "hrtimeBuffer"), ab) |
475 | | - .ToChecked(); |
476 | | - backing_store_ = ab->GetBackingStore(); |
| 477 | + |
| 478 | + if (info == nullptr) { |
| 479 | + object |
| 480 | + ->Set(context, |
| 481 | + FIXED_ONE_BYTE_STRING(isolate, "hrtimeBuffer"), |
| 482 | + hrtime_buffer_.GetJSArray()) |
| 483 | + .ToChecked(); |
| 484 | + } else { |
| 485 | + hrtime_buffer_.Deserialize(realm->context()); |
| 486 | + } |
| 487 | + |
| 488 | + // The hrtime buffer is referenced from the binding data js object. |
| 489 | + // Make the native handle weak to avoid keeping the realm alive. |
| 490 | + hrtime_buffer_.MakeWeak(); |
477 | 491 | } |
478 | 492 |
|
479 | 493 | v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber)); |
@@ -503,7 +517,7 @@ BindingData* BindingData::FromV8Value(Local<Value> value) { |
503 | 517 | } |
504 | 518 |
|
505 | 519 | void BindingData::MemoryInfo(MemoryTracker* tracker) const { |
506 | | - tracker->TrackField("array_buffer", array_buffer_); |
| 520 | + tracker->TrackField("hrtime_buffer", hrtime_buffer_); |
507 | 521 | } |
508 | 522 |
|
509 | 523 | // This is the legacy version of hrtime before BigInt was introduced in |
@@ -516,20 +530,19 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { |
516 | 530 | // because there is no Uint64Array in JS. |
517 | 531 | // The third entry contains the remaining nanosecond part of the value. |
518 | 532 | void BindingData::NumberImpl(BindingData* receiver) { |
519 | | - // Make sure we don't accidentally access buffers wiped for snapshot. |
520 | | - CHECK(!receiver->array_buffer_.IsEmpty()); |
521 | 533 | uint64_t t = uv_hrtime(); |
522 | | - uint32_t* fields = static_cast<uint32_t*>(receiver->backing_store_->Data()); |
523 | | - fields[0] = (t / NANOS_PER_SEC) >> 32; |
524 | | - fields[1] = (t / NANOS_PER_SEC) & 0xffffffff; |
525 | | - fields[2] = t % NANOS_PER_SEC; |
| 534 | + receiver->hrtime_buffer_[0] = (t / NANOS_PER_SEC) >> 32; |
| 535 | + receiver->hrtime_buffer_[1] = (t / NANOS_PER_SEC) & 0xffffffff; |
| 536 | + receiver->hrtime_buffer_[2] = t % NANOS_PER_SEC; |
526 | 537 | } |
527 | 538 |
|
528 | 539 | void BindingData::BigIntImpl(BindingData* receiver) { |
529 | | - // Make sure we don't accidentally access buffers wiped for snapshot. |
530 | | - CHECK(!receiver->array_buffer_.IsEmpty()); |
531 | 540 | uint64_t t = uv_hrtime(); |
532 | | - uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data()); |
| 541 | + // The buffer is a Uint32Array, so we need to reinterpret it as a |
| 542 | + // Uint64Array to write the value. The buffer is valid at this scope so we |
| 543 | + // can safely cast away the constness. |
| 544 | + uint64_t* fields = reinterpret_cast<uint64_t*>( |
| 545 | + const_cast<uint32_t*>(receiver->hrtime_buffer_.GetNativeBuffer())); |
533 | 546 | fields[0] = t; |
534 | 547 | } |
535 | 548 |
|
@@ -543,18 +556,19 @@ void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) { |
543 | 556 |
|
544 | 557 | bool BindingData::PrepareForSerialization(Local<Context> context, |
545 | 558 | v8::SnapshotCreator* creator) { |
546 | | - // It's not worth keeping. |
547 | | - // Release it, we will recreate it when the instance is dehydrated. |
548 | | - array_buffer_.Reset(); |
| 559 | + DCHECK_NULL(internal_field_info_); |
| 560 | + internal_field_info_ = InternalFieldInfoBase::New<InternalFieldInfo>(type()); |
| 561 | + internal_field_info_->hrtime_buffer = |
| 562 | + hrtime_buffer_.Serialize(context, creator); |
549 | 563 | // Return true because we need to maintain the reference to the binding from |
550 | 564 | // JS land. |
551 | 565 | return true; |
552 | 566 | } |
553 | 567 |
|
554 | 568 | InternalFieldInfoBase* BindingData::Serialize(int index) { |
555 | 569 | DCHECK_IS_SNAPSHOT_SLOT(index); |
556 | | - InternalFieldInfo* info = |
557 | | - InternalFieldInfoBase::New<InternalFieldInfo>(type()); |
| 570 | + InternalFieldInfo* info = internal_field_info_; |
| 571 | + internal_field_info_ = nullptr; |
558 | 572 | return info; |
559 | 573 | } |
560 | 574 |
|
@@ -566,7 +580,9 @@ void BindingData::Deserialize(Local<Context> context, |
566 | 580 | v8::HandleScope scope(context->GetIsolate()); |
567 | 581 | Realm* realm = Realm::GetCurrent(context); |
568 | 582 | // Recreate the buffer in the constructor. |
569 | | - BindingData* binding = realm->AddBindingData<BindingData>(holder); |
| 583 | + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); |
| 584 | + BindingData* binding = |
| 585 | + realm->AddBindingData<BindingData>(holder, casted_info); |
570 | 586 | CHECK_NOT_NULL(binding); |
571 | 587 | } |
572 | 588 |
|
|