| Index: src/serialize.cc
|
| diff --git a/src/serialize.cc b/src/serialize.cc
|
| index e6aae7fe8de90260da6f3e1e1463ab3544de8cea..f0bd68e659bc1a0377011bce6b544e2dcdc61ed5 100644
|
| --- a/src/serialize.cc
|
| +++ b/src/serialize.cc
|
| @@ -611,12 +611,16 @@ class CodeAddressMap: public CodeEventLogger {
|
| };
|
|
|
|
|
| -Deserializer::Deserializer(SnapshotByteSource* source)
|
| - : isolate_(NULL),
|
| - attached_objects_(NULL),
|
| - source_(source),
|
| - external_reference_decoder_(NULL),
|
| - deserialized_large_objects_(0) {
|
| +void Deserializer::DecodeReservation(
|
| + Vector<const SerializedData::Reservation> res) {
|
| + DCHECK_EQ(0, reservations_[NEW_SPACE].length());
|
| + STATIC_ASSERT(NEW_SPACE == 0);
|
| + int current_space = NEW_SPACE;
|
| + for (const auto& r : res) {
|
| + reservations_[current_space].Add({r.chunk_size(), NULL, NULL});
|
| + if (r.is_last()) current_space++;
|
| + }
|
| + DCHECK_EQ(kNumberOfSpaces, current_space);
|
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0;
|
| }
|
|
|
| @@ -716,7 +720,7 @@ void Deserializer::DeserializePartial(Isolate* isolate, Object** root,
|
|
|
| Deserializer::~Deserializer() {
|
| // TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed.
|
| - // DCHECK(source_->AtEOF());
|
| + // DCHECK(source_.AtEOF());
|
| if (external_reference_decoder_) {
|
| delete external_reference_decoder_;
|
| external_reference_decoder_ = NULL;
|
| @@ -797,10 +801,10 @@ HeapObject* Deserializer::ProcessNewObjectFromSerializedCode(HeapObject* obj) {
|
| HeapObject* Deserializer::GetBackReferencedObject(int space) {
|
| HeapObject* obj;
|
| if (space == LO_SPACE) {
|
| - uint32_t index = source_->GetInt();
|
| + uint32_t index = source_.GetInt();
|
| obj = deserialized_large_objects_[index];
|
| } else {
|
| - BackReference back_reference(source_->GetInt());
|
| + BackReference back_reference(source_.GetInt());
|
| DCHECK(space < kNumberOfPreallocatedSpaces);
|
| uint32_t chunk_index = back_reference.chunk_index();
|
| DCHECK_LE(chunk_index, current_chunk_[space]);
|
| @@ -824,12 +828,12 @@ HeapObject* Deserializer::GetBackReferencedObject(int space) {
|
| void Deserializer::ReadObject(int space_number, Object** write_back) {
|
| Address address;
|
| HeapObject* obj;
|
| - int next_int = source_->GetInt();
|
| + int next_int = source_.GetInt();
|
|
|
| bool double_align = false;
|
| #ifndef V8_HOST_ARCH_64_BIT
|
| double_align = next_int == kDoubleAlignmentSentinel;
|
| - if (double_align) next_int = source_->GetInt();
|
| + if (double_align) next_int = source_.GetInt();
|
| #endif
|
|
|
| DCHECK_NE(kDoubleAlignmentSentinel, next_int);
|
| @@ -846,7 +850,7 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
|
| Object** current = reinterpret_cast<Object**>(address);
|
| Object** limit = current + (size >> kPointerSizeLog2);
|
| if (FLAG_log_snapshot_positions) {
|
| - LOG(isolate_, SnapshotPositionEvent(address, source_->position()));
|
| + LOG(isolate_, SnapshotPositionEvent(address, source_.position()));
|
| }
|
| ReadData(current, limit, space_number, address);
|
|
|
| @@ -884,7 +888,7 @@ Address Deserializer::Allocate(int space_index, int size) {
|
| if (space_index == LO_SPACE) {
|
| AlwaysAllocateScope scope(isolate_);
|
| LargeObjectSpace* lo_space = isolate_->heap()->lo_space();
|
| - Executability exec = static_cast<Executability>(source_->Get());
|
| + Executability exec = static_cast<Executability>(source_.Get());
|
| AllocationResult result = lo_space->AllocateRaw(size, exec);
|
| HeapObject* obj = HeapObject::cast(result.ToObjectChecked());
|
| deserialized_large_objects_.Add(obj);
|
| @@ -918,7 +922,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| source_space != CODE_SPACE &&
|
| source_space != OLD_DATA_SPACE);
|
| while (current < limit) {
|
| - byte data = source_->Get();
|
| + byte data = source_.Get();
|
| switch (data) {
|
| #define CASE_STATEMENT(where, how, within, space_number) \
|
| case where + how + within + space_number: \
|
| @@ -942,18 +946,18 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| if (where == kNewObject) { \
|
| ReadObject(space_number, &new_object); \
|
| } else if (where == kRootArray) { \
|
| - int root_id = source_->GetInt(); \
|
| + int root_id = source_.GetInt(); \
|
| new_object = isolate->heap()->roots_array_start()[root_id]; \
|
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
|
| } else if (where == kPartialSnapshotCache) { \
|
| - int cache_index = source_->GetInt(); \
|
| + int cache_index = source_.GetInt(); \
|
| new_object = isolate->serialize_partial_snapshot_cache()[cache_index]; \
|
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
|
| } else if (where == kExternalReference) { \
|
| - int skip = source_->GetInt(); \
|
| + int skip = source_.GetInt(); \
|
| current = reinterpret_cast<Object**>( \
|
| reinterpret_cast<Address>(current) + skip); \
|
| - int reference_id = source_->GetInt(); \
|
| + int reference_id = source_.GetInt(); \
|
| Address address = external_reference_decoder_->Decode(reference_id); \
|
| new_object = reinterpret_cast<Object*>(address); \
|
| } else if (where == kBackref) { \
|
| @@ -961,7 +965,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| new_object = GetBackReferencedObject(data & kSpaceMask); \
|
| } else if (where == kBuiltin) { \
|
| DCHECK(deserializing_user_code()); \
|
| - int builtin_id = source_->GetInt(); \
|
| + int builtin_id = source_.GetInt(); \
|
| DCHECK_LE(0, builtin_id); \
|
| DCHECK_LT(builtin_id, Builtins::builtin_count); \
|
| Builtins::Name name = static_cast<Builtins::Name>(builtin_id); \
|
| @@ -969,12 +973,12 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| emit_write_barrier = false; \
|
| } else if (where == kAttachedReference) { \
|
| DCHECK(deserializing_user_code()); \
|
| - int index = source_->GetInt(); \
|
| + int index = source_.GetInt(); \
|
| new_object = *attached_objects_->at(index); \
|
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
|
| } else { \
|
| DCHECK(where == kBackrefWithSkip); \
|
| - int skip = source_->GetInt(); \
|
| + int skip = source_.GetInt(); \
|
| current = reinterpret_cast<Object**>( \
|
| reinterpret_cast<Address>(current) + skip); \
|
| emit_write_barrier = (space_number == NEW_SPACE); \
|
| @@ -1078,23 +1082,22 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
|
|
| // We generate 15 cases and bodies that process special tags that combine
|
| // the raw data tag and the length into one byte.
|
| -#define RAW_CASE(index) \
|
| - case kRawData + index: { \
|
| - byte* raw_data_out = reinterpret_cast<byte*>(current); \
|
| - source_->CopyRaw(raw_data_out, index * kPointerSize); \
|
| - current = \
|
| - reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \
|
| - break; \
|
| - }
|
| +#define RAW_CASE(index) \
|
| + case kRawData + index: { \
|
| + byte* raw_data_out = reinterpret_cast<byte*>(current); \
|
| + source_.CopyRaw(raw_data_out, index* kPointerSize); \
|
| + current = reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \
|
| + break; \
|
| + }
|
| COMMON_RAW_LENGTHS(RAW_CASE)
|
| #undef RAW_CASE
|
|
|
| // Deserialize a chunk of raw data that doesn't have one of the popular
|
| // lengths.
|
| case kRawData: {
|
| - int size = source_->GetInt();
|
| + int size = source_.GetInt();
|
| byte* raw_data_out = reinterpret_cast<byte*>(current);
|
| - source_->CopyRaw(raw_data_out, size);
|
| + source_.CopyRaw(raw_data_out, size);
|
| break;
|
| }
|
|
|
| @@ -1110,7 +1113,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance)
|
| SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance + 16) {
|
| int root_id = RootArrayConstantFromByteCode(data);
|
| - int skip = source_->GetInt();
|
| + int skip = source_.GetInt();
|
| current = reinterpret_cast<Object**>(
|
| reinterpret_cast<intptr_t>(current) + skip);
|
| Object* object = isolate->heap()->roots_array_start()[root_id];
|
| @@ -1120,7 +1123,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| }
|
|
|
| case kVariableRepeat: {
|
| - int repeats = source_->GetInt();
|
| + int repeats = source_.GetInt();
|
| Object* object = current[-1];
|
| DCHECK(!isolate->heap()->InNewSpace(object));
|
| for (int i = 0; i < repeats; i++) current[i] = object;
|
| @@ -1240,14 +1243,14 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| #undef ALL_SPACES
|
|
|
| case kSkip: {
|
| - int size = source_->GetInt();
|
| + int size = source_.GetInt();
|
| current = reinterpret_cast<Object**>(
|
| reinterpret_cast<intptr_t>(current) + size);
|
| break;
|
| }
|
|
|
| case kNativesStringResource: {
|
| - int index = source_->Get();
|
| + int index = source_.Get();
|
| Vector<const char> source_vector = Natives::GetRawScriptSource(index);
|
| NativesExternalStringResource* resource =
|
| new NativesExternalStringResource(isolate->bootstrapper(),
|
| @@ -1258,7 +1261,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
| }
|
|
|
| case kNextChunk: {
|
| - int space = source_->Get();
|
| + int space = source_.Get();
|
| DCHECK(space < kNumberOfPreallocatedSpaces);
|
| int chunk_index = current_chunk_[space];
|
| const Heap::Reservation& reservation = reservations_[space];
|
| @@ -1273,7 +1276,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
|
|
|
| FOUR_CASES(kHotObjectWithSkip)
|
| FOUR_CASES(kHotObjectWithSkip + 4) {
|
| - int skip = source_->GetInt();
|
| + int skip = source_.GetInt();
|
| current = reinterpret_cast<Object**>(
|
| reinterpret_cast<Address>(current) + skip);
|
| // Fall through.
|
| @@ -1394,15 +1397,21 @@ void Serializer::VisitPointers(Object** start, Object** end) {
|
| }
|
|
|
|
|
| -void Serializer::FinalizeAllocation() {
|
| +void Serializer::EncodeReservations(
|
| + List<SerializedData::Reservation>* out) const {
|
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
|
| - // Complete the last pending chunk and if there are no completed chunks,
|
| - // make sure there is at least one empty chunk.
|
| + for (int j = 0; j < completed_chunks_[i].length(); j++) {
|
| + out->Add(SerializedData::Reservation(completed_chunks_[i][j]));
|
| + }
|
| +
|
| if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) {
|
| - completed_chunks_[i].Add(pending_chunk_[i]);
|
| - pending_chunk_[i] = 0;
|
| + out->Add(SerializedData::Reservation(pending_chunk_[i]));
|
| }
|
| + out->last().mark_as_last();
|
| }
|
| +
|
| + out->Add(SerializedData::Reservation(large_objects_total_size_));
|
| + out->last().mark_as_last();
|
| }
|
|
|
|
|
| @@ -1718,7 +1727,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
|
| }
|
|
|
| // Serialize string content.
|
| - sink_->PutRaw(const_cast<byte*>(resource), content_size, "StringContent");
|
| + sink_->PutRaw(resource, content_size, "StringContent");
|
|
|
| // Since the allocation size is rounded up to object alignment, there
|
| // maybe left-over bytes that need to be padded.
|
| @@ -2021,6 +2030,7 @@ BackReference Serializer::Allocate(AllocationSpace space, int size) {
|
| sink_->Put(kNextChunk, "NextChunk");
|
| sink_->Put(space, "NextChunkSpace");
|
| completed_chunks_[space].Add(pending_chunk_[space]);
|
| + DCHECK_LE(completed_chunks_[space].length(), BackReference::kMaxChunkIndex);
|
| pending_chunk_[space] = 0;
|
| new_chunk_size = size;
|
| }
|
| @@ -2065,16 +2075,8 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate,
|
| Object** location = Handle<Object>::cast(info).location();
|
| cs.VisitPointer(location);
|
| cs.Pad();
|
| - cs.FinalizeAllocation();
|
| -
|
| - for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
|
| - // Fail if any chunk index exceeds the limit.
|
| - if (cs.FinalAllocationChunks(i).length() > BackReference::kMaxChunkIndex) {
|
| - return NULL;
|
| - }
|
| - }
|
|
|
| - SerializedCodeData data(sink.data(), &cs);
|
| + SerializedCodeData data(sink.data(), cs);
|
| ScriptData* script_data = data.GetScriptData();
|
|
|
| if (FLAG_profile_deserialization) {
|
| @@ -2275,23 +2277,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
| DCHECK(cached_data->rejected());
|
| return MaybeHandle<SharedFunctionInfo>();
|
| }
|
| - SnapshotByteSource payload(scd->Payload(), scd->PayloadLength());
|
| - Deserializer deserializer(&payload);
|
|
|
| // Eagerly expand string table to avoid allocations during deserialization.
|
| StringTable::EnsureCapacityForDeserialization(
|
| isolate, scd->NumInternalizedStrings());
|
|
|
| - // Set reservations.
|
| - STATIC_ASSERT(NEW_SPACE == 0);
|
| - int current_space = NEW_SPACE;
|
| - Vector<const SerializedCodeData::Reservation> res = scd->Reservations();
|
| - for (const auto& r : res) {
|
| - deserializer.AddReservation(current_space, r.chunk_size());
|
| - if (r.is_last_chunk()) current_space++;
|
| - }
|
| - DCHECK_EQ(kNumberOfSpaces, current_space);
|
| -
|
| // Prepare and register list of attached objects.
|
| Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys();
|
| Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
|
| @@ -2301,6 +2291,8 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
| attached_objects[i + kCodeStubsBaseIndex] =
|
| CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
|
| }
|
| +
|
| + Deserializer deserializer(scd.get());
|
| deserializer.SetAttachedObjects(&attached_objects);
|
|
|
| // Deserialize.
|
| @@ -2336,65 +2328,152 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
| }
|
|
|
|
|
| +void SerializedData::AllocateData(int size) {
|
| + DCHECK(!owns_data_);
|
| + data_ = NewArray<byte>(size);
|
| + size_ = size;
|
| + owns_data_ = true;
|
| + DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
|
| +}
|
| +
|
| +
|
| +SnapshotData::SnapshotData(const SnapshotByteSink& sink,
|
| + const Serializer& ser) {
|
| + DisallowHeapAllocation no_gc;
|
| + List<Reservation> reservations;
|
| + ser.EncodeReservations(&reservations);
|
| + const List<byte>& payload = sink.data();
|
| +
|
| + // Calculate sizes.
|
| + int reservation_size = reservations.length() * kInt32Size;
|
| + int size = kHeaderSize + reservation_size + payload.length();
|
| +
|
| + // Allocate backing store and create result data.
|
| + AllocateData(size);
|
| +
|
| + // Set header values.
|
| + SetHeaderValue(kCheckSumOffset, Version::Hash());
|
| + SetHeaderValue(kReservationsOffset, reservations.length());
|
| + SetHeaderValue(kPayloadLengthOffset, payload.length());
|
| +
|
| + // Copy reservation chunk sizes.
|
| + CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
|
| + reservation_size);
|
| +
|
| + // Copy serialized data.
|
| + CopyBytes(data_ + kHeaderSize + reservation_size, payload.begin(),
|
| + static_cast<size_t>(payload.length()));
|
| +}
|
| +
|
| +
|
| +bool SnapshotData::IsSane() {
|
| + return GetHeaderValue(kCheckSumOffset) == Version::Hash();
|
| +}
|
| +
|
| +
|
| +Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
|
| + return Vector<const Reservation>(
|
| + reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
|
| + GetHeaderValue(kReservationsOffset));
|
| +}
|
| +
|
| +
|
| +Vector<const byte> SnapshotData::Payload() const {
|
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
|
| + const byte* payload = data_ + kHeaderSize + reservations_size;
|
| + int length = GetHeaderValue(kPayloadLengthOffset);
|
| + DCHECK_EQ(data_ + size_, payload + length);
|
| + return Vector<const byte>(payload, length);
|
| +}
|
| +
|
| +
|
| SerializedCodeData::SerializedCodeData(const List<byte>& payload,
|
| - CodeSerializer* cs)
|
| - : script_data_(NULL), owns_script_data_(true) {
|
| + const CodeSerializer& cs) {
|
| DisallowHeapAllocation no_gc;
|
| - List<uint32_t>* stub_keys = cs->stub_keys();
|
| + const List<uint32_t>* stub_keys = cs.stub_keys();
|
|
|
| - // Gather reservation chunk sizes.
|
| - List<uint32_t> reservations(SerializerDeserializer::kNumberOfSpaces);
|
| - STATIC_ASSERT(NEW_SPACE == 0);
|
| - for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) {
|
| - Vector<const uint32_t> chunks = cs->FinalAllocationChunks(i);
|
| - for (int j = 0; j < chunks.length(); j++) {
|
| - uint32_t chunk = ChunkSizeBits::encode(chunks[j]) |
|
| - IsLastChunkBits::encode(j == chunks.length() - 1);
|
| - reservations.Add(chunk);
|
| - }
|
| - }
|
| + List<Reservation> reservations;
|
| + cs.EncodeReservations(&reservations);
|
|
|
| // Calculate sizes.
|
| int reservation_size = reservations.length() * kInt32Size;
|
| int num_stub_keys = stub_keys->length();
|
| int stub_keys_size = stub_keys->length() * kInt32Size;
|
| - int data_length =
|
| - kHeaderSize + reservation_size + stub_keys_size + payload.length();
|
| + int size = kHeaderSize + reservation_size + stub_keys_size + payload.length();
|
|
|
| // Allocate backing store and create result data.
|
| - byte* data = NewArray<byte>(data_length);
|
| - DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
|
| - script_data_ = new ScriptData(data, data_length);
|
| - script_data_->AcquireDataOwnership();
|
| + AllocateData(size);
|
|
|
| // Set header values.
|
| - SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
|
| - SetHeaderValue(kNumInternalizedStringsOffset, cs->num_internalized_strings());
|
| + SetHeaderValue(kCheckSumOffset, CheckSum(cs.source()));
|
| + SetHeaderValue(kNumInternalizedStringsOffset, cs.num_internalized_strings());
|
| SetHeaderValue(kReservationsOffset, reservations.length());
|
| SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
|
| SetHeaderValue(kPayloadLengthOffset, payload.length());
|
|
|
| // Copy reservation chunk sizes.
|
| - CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
|
| + CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
|
| reservation_size);
|
|
|
| // Copy code stub keys.
|
| - CopyBytes(data + kHeaderSize + reservation_size,
|
| + CopyBytes(data_ + kHeaderSize + reservation_size,
|
| reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size);
|
|
|
| // Copy serialized data.
|
| - CopyBytes(data + kHeaderSize + reservation_size + stub_keys_size,
|
| + CopyBytes(data_ + kHeaderSize + reservation_size + stub_keys_size,
|
| payload.begin(), static_cast<size_t>(payload.length()));
|
| }
|
|
|
|
|
| bool SerializedCodeData::IsSane(String* source) {
|
| return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
|
| - PayloadLength() >= SharedFunctionInfo::kSize;
|
| + Payload().length() >= SharedFunctionInfo::kSize;
|
| }
|
|
|
|
|
| int SerializedCodeData::CheckSum(String* string) {
|
| return Version::Hash() ^ string->length();
|
| }
|
| +
|
| +
|
| +// Return ScriptData object and relinquish ownership over it to the caller.
|
| +ScriptData* SerializedCodeData::GetScriptData() {
|
| + DCHECK(owns_data_);
|
| + ScriptData* result = new ScriptData(data_, size_);
|
| + result->AcquireDataOwnership();
|
| + owns_data_ = false;
|
| + data_ = NULL;
|
| + return result;
|
| +}
|
| +
|
| +
|
| +Vector<const SerializedData::Reservation> SerializedCodeData::Reservations()
|
| + const {
|
| + return Vector<const Reservation>(
|
| + reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
|
| + GetHeaderValue(kReservationsOffset));
|
| +}
|
| +
|
| +
|
| +Vector<const byte> SerializedCodeData::Payload() const {
|
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
|
| + int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
|
| + const byte* payload =
|
| + data_ + kHeaderSize + reservations_size + code_stubs_size;
|
| + int length = GetHeaderValue(kPayloadLengthOffset);
|
| + DCHECK_EQ(data_ + size_, payload + length);
|
| + return Vector<const byte>(payload, length);
|
| +}
|
| +
|
| +
|
| +int SerializedCodeData::NumInternalizedStrings() const {
|
| + return GetHeaderValue(kNumInternalizedStringsOffset);
|
| +}
|
| +
|
| +Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
|
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
|
| + const byte* start = data_ + kHeaderSize + reservations_size;
|
| + return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start),
|
| + GetHeaderValue(kNumCodeStubKeysOffset));
|
| +}
|
| } } // namespace v8::internal
|
|
|