blob: 62f7ea39e032cf6ae031d3054babad144dae7df8 [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_SNAPSHOT_DESERIALIZER_H_
#define V8_SNAPSHOT_DESERIALIZER_H_
#include <utility>
#include <vector>
#include "src/common/globals.h"
#include "src/objects/allocation-site.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/backing-store.h"
#include "src/objects/code.h"
#include "src/objects/js-array.h"
#include "src/objects/map.h"
#include "src/objects/string-table.h"
#include "src/objects/string.h"
#include "src/snapshot/serializer-deserializer.h"
#include "src/snapshot/snapshot-source-sink.h"
namespace v8 {
namespace internal {
class HeapObject;
class Object;
// Used for platforms with embedded constant pools to trigger deserialization
// of objects found in code.
#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \
defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390) || \
defined(V8_TARGET_ARCH_PPC64) || V8_EMBEDDED_CONSTANT_POOL
#define V8_CODE_EMBEDS_OBJECT_POINTER 1
#else
#define V8_CODE_EMBEDS_OBJECT_POINTER 0
#endif
// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
public:
// Smi value for filling in not-yet initialized tagged field values with a
// valid tagged pointer. A field value equal to this doesn't necessarily
// indicate that a field is uninitialized, but an uninitialized field should
// definitely equal this value.
//
// This _has_ to be kNullAddress, so that an uninitialized_field_value read as
// an embedded pointer field is interpreted as nullptr. This is so that
// uninitialised embedded pointers are not forwarded to the embedded as part
// of embedder tracing (and similar mechanisms), as nullptrs are skipped for
// those cases and otherwise the embedder would try to dereference the
// uninitialized pointer value.
static constexpr Smi uninitialized_field_value() { return Smi(kNullAddress); }
~Deserializer() override;
Deserializer(const Deserializer&) = delete;
Deserializer& operator=(const Deserializer&) = delete;
uint32_t GetChecksum() const { return source_.GetChecksum(); }
protected:
// Create a deserializer from a snapshot byte source.
Deserializer(Isolate* isolate, Vector<const byte> payload,
uint32_t magic_number, bool deserializing_user_code,
bool can_rehash);
void DeserializeDeferredObjects();
// Create Log events for newly deserialized objects.
void LogNewObjectEvents();
void LogScriptEvents(Script script);
void LogNewMapEvents();
// Descriptor arrays are deserialized as "strong", so that there is no risk of
// them getting trimmed during a partial deserialization. This method makes
// them "weak" again after deserialization completes.
void WeakenDescriptorArrays();
// This returns the address of an object that has been described in the
// snapshot by object vector index.
Handle<HeapObject> GetBackReferencedObject();
// Add an object to back an attached reference. The order to add objects must
// mirror the order they are added in the serializer.
void AddAttachedObject(Handle<HeapObject> attached_object) {
attached_objects_.push_back(attached_object);
}
void CheckNoArrayBufferBackingStores() {
CHECK_EQ(new_off_heap_array_buffers().size(), 0);
}
Isolate* isolate() const { return isolate_; }
SnapshotByteSource* source() { return &source_; }
const std::vector<Handle<AllocationSite>>& new_allocation_sites() const {
return new_allocation_sites_;
}
const std::vector<Handle<Code>>& new_code_objects() const {
return new_code_objects_;
}
const std::vector<Handle<Map>>& new_maps() const { return new_maps_; }
const std::vector<Handle<AccessorInfo>>& accessor_infos() const {
return accessor_infos_;
}
const std::vector<Handle<CallHandlerInfo>>& call_handler_infos() const {
return call_handler_infos_;
}
const std::vector<Handle<Script>>& new_scripts() const {
return new_scripts_;
}
const std::vector<Handle<JSArrayBuffer>>& new_off_heap_array_buffers() const {
return new_off_heap_array_buffers_;
}
const std::vector<Handle<DescriptorArray>>& new_descriptor_arrays() const {
return new_descriptor_arrays_;
}
std::shared_ptr<BackingStore> backing_store(size_t i) {
DCHECK_LT(i, backing_stores_.size());
return backing_stores_[i];
}
bool deserializing_user_code() const { return deserializing_user_code_; }
bool can_rehash() const { return can_rehash_; }
void Rehash();
Handle<HeapObject> ReadObject();
private:
class RelocInfoVisitor;
// A circular queue of hot objects. This is added to in the same order as in
// Serializer::HotObjectsList, but this stores the objects as a vector of
// existing handles. This allows us to add Handles to the queue without having
// to create new handles. Note that this depends on those Handles staying
// valid as long as the HotObjectsList is alive.
class HotObjectsList {
public:
HotObjectsList() = default;
HotObjectsList(const HotObjectsList&) = delete;
HotObjectsList& operator=(const HotObjectsList&) = delete;
void Add(Handle<HeapObject> object) {
circular_queue_[index_] = object;
index_ = (index_ + 1) & kSizeMask;
}
Handle<HeapObject> Get(int index) {
DCHECK(!circular_queue_[index].is_null());
return circular_queue_[index];
}
private:
static const int kSize = kHotObjectCount;
static const int kSizeMask = kSize - 1;
STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
Handle<HeapObject> circular_queue_[kSize];
int index_ = 0;
};
void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override;
void Synchronize(VisitorSynchronization::SyncTag tag) override;
template <typename TSlot>
inline int WriteAddress(TSlot dest, Address value);
template <typename TSlot>
inline int WriteExternalPointer(TSlot dest, Address value,
ExternalPointerTag tag);
// Fills in a heap object's data from start to end (exclusive). Start and end
// are slot indices within the object.
void ReadData(Handle<HeapObject> object, int start_slot_index,
int end_slot_index);
// Fills in a contiguous range of full object slots (e.g. root pointers) from
// start to end (exclusive).
void ReadData(FullMaybeObjectSlot start, FullMaybeObjectSlot end);
// Helper for ReadData which reads the given bytecode and fills in some heap
// data into the given slot. May fill in zero or multiple slots, so it returns
// the number of slots filled.
template <typename SlotAccessor>
int ReadSingleBytecodeData(byte data, SlotAccessor slot_accessor);
// A helper function for ReadData for reading external references.
inline Address ReadExternalReferenceCase();
Handle<HeapObject> ReadObject(SnapshotSpace space_number);
Handle<HeapObject> ReadMetaMap();
HeapObjectReferenceType GetAndResetNextReferenceType();
template <typename SlotGetter>
int ReadRepeatedObject(SlotGetter slot_getter, int repeat_count);
// Special handling for serialized code like hooking up internalized strings.
void PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
SnapshotSpace space);
HeapObject Allocate(SnapshotSpace space, int size,
AllocationAlignment alignment);
// Cached current isolate.
Isolate* isolate_;
// Objects from the attached object descriptions in the serialized user code.
std::vector<Handle<HeapObject>> attached_objects_;
SnapshotByteSource source_;
uint32_t magic_number_;
HotObjectsList hot_objects_;
std::vector<Handle<Map>> new_maps_;
std::vector<Handle<AllocationSite>> new_allocation_sites_;
std::vector<Handle<Code>> new_code_objects_;
std::vector<Handle<AccessorInfo>> accessor_infos_;
std::vector<Handle<CallHandlerInfo>> call_handler_infos_;
std::vector<Handle<Script>> new_scripts_;
std::vector<Handle<JSArrayBuffer>> new_off_heap_array_buffers_;
std::vector<Handle<DescriptorArray>> new_descriptor_arrays_;
std::vector<std::shared_ptr<BackingStore>> backing_stores_;
// Vector of allocated objects that can be accessed by a backref, by index.
std::vector<Handle<HeapObject>> back_refs_;
// Unresolved forward references (registered with kRegisterPendingForwardRef)
// are collected in order as (object, field offset) pairs. The subsequent
// forward ref resolution (with kResolvePendingForwardRef) accesses this
// vector by index.
//
// The vector is cleared when there are no more unresolved forward refs.
struct UnresolvedForwardRef {
UnresolvedForwardRef(Handle<HeapObject> object, int offset,
HeapObjectReferenceType ref_type)
: object(object), offset(offset), ref_type(ref_type) {}
Handle<HeapObject> object;
int offset;
HeapObjectReferenceType ref_type;
};
std::vector<UnresolvedForwardRef> unresolved_forward_refs_;
int num_unresolved_forward_refs_ = 0;
const bool deserializing_user_code_;
bool next_reference_is_weak_ = false;
// TODO(6593): generalize rehashing, and remove this flag.
bool can_rehash_;
std::vector<Handle<HeapObject>> to_rehash_;
#ifdef DEBUG
uint32_t num_api_references_;
// Record the previous object allocated for DCHECKs.
Handle<HeapObject> previous_allocation_obj_;
int previous_allocation_size_ = 0;
#endif // DEBUG
};
// Used to insert a deserialized internalized string into the string table.
class StringTableInsertionKey final : public StringTableKey {
public:
explicit StringTableInsertionKey(Handle<String> string);
bool IsMatch(String string) override;
V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate);
V8_WARN_UNUSED_RESULT Handle<String> AsHandle(LocalIsolate* isolate);
private:
uint32_t ComputeHashField(String string);
Handle<String> string_;
DISALLOW_HEAP_ALLOCATION(no_gc)
};
} // namespace internal
} // namespace v8
#endif // V8_SNAPSHOT_DESERIALIZER_H_