// Copyright 2017 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_BUILTIN_DESERIALIZER_ALLOCATOR_H_ #define V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_ #include #include "src/globals.h" #include "src/heap/heap.h" #include "src/interpreter/interpreter.h" #include "src/snapshot/serializer-common.h" namespace v8 { namespace internal { template class Deserializer; class BuiltinDeserializer; class BuiltinSnapshotUtils; class BuiltinDeserializerAllocator final { using BSU = BuiltinSnapshotUtils; using Bytecode = interpreter::Bytecode; using OperandScale = interpreter::OperandScale; public: BuiltinDeserializerAllocator( Deserializer* deserializer); ~BuiltinDeserializerAllocator(); // ------- Allocation Methods ------- // Methods related to memory allocation during deserialization. // Allocation works differently here than in other deserializers. Instead of // a statically-known memory area determined at serialization-time, our // memory requirements here are determined at runtime. Another major // difference is that we create builtin Code objects up-front (before // deserialization) in order to avoid having to patch builtin references // later on. See also the kBuiltin case in deserializer.cc. // // There are three ways that we use to reserve / allocate space. In all // cases, required objects are requested from the GC prior to // deserialization. 1. pre-allocated builtin code objects are written into // the builtins table (this is to make deserialization of builtin references // easier). Pre-allocated handler code objects are 2. stored in the // {handler_allocations_} vector (at eager-deserialization time) and 3. // stored in {handler_allocation_} (at lazy-deserialization time). // // Allocate simply returns the pre-allocated object prepared by // InitializeFromReservations. Address Allocate(AllocationSpace space, int size); void MoveToNextChunk(AllocationSpace space) { UNREACHABLE(); } void SetAlignment(AllocationAlignment alignment) { UNREACHABLE(); } void set_next_reference_is_weak(bool next_reference_is_weak) { next_reference_is_weak_ = next_reference_is_weak; } bool GetAndClearNextReferenceIsWeak() { bool saved = next_reference_is_weak_; next_reference_is_weak_ = false; return saved; } #ifdef DEBUG bool next_reference_is_weak() const { return next_reference_is_weak_; } #endif HeapObject* GetMap(uint32_t index) { UNREACHABLE(); } HeapObject* GetLargeObject(uint32_t index) { UNREACHABLE(); } HeapObject* GetObject(AllocationSpace space, uint32_t chunk_index, uint32_t chunk_offset) { UNREACHABLE(); } // ------- Reservation Methods ------- // Methods related to memory reservations (prior to deserialization). // Builtin deserialization does not bake reservations into the snapshot, hence // this is a nop. void DecodeReservation(std::vector res) {} // These methods are used to pre-allocate builtin objects prior to // deserialization. // TODO(jgruber): Refactor reservation/allocation logic in deserializers to // make this less messy. Heap::Reservation CreateReservationsForEagerBuiltinsAndHandlers(); void InitializeFromReservations(const Heap::Reservation& reservation); // Creates reservations and initializes the builtins table in preparation for // lazily deserializing a single builtin. void ReserveAndInitializeBuiltinsTableForBuiltin(int builtin_id); // Pre-allocates a code object preparation for lazily deserializing a single // handler. void ReserveForHandler(Bytecode bytecode, OperandScale operand_scale); #ifdef DEBUG bool ReservationsAreFullyUsed() const; #endif private: Isolate* isolate() const; BuiltinDeserializer* deserializer() const; // Used after memory allocation prior to isolate initialization, to register // the newly created object in code space and add it to the builtins table. void InitializeBuiltinFromReservation(const Heap::Chunk& chunk, int builtin_id); // As above, but for interpreter bytecode handlers. void InitializeHandlerFromReservation( const Heap::Chunk& chunk, interpreter::Bytecode bytecode, interpreter::OperandScale operand_scale); #ifdef DEBUG void RegisterCodeObjectReservation(int code_object_id); void RegisterCodeObjectAllocation(int code_object_id); std::unordered_set unused_reservations_; #endif private: // The current deserializer. Note that this always points to a // BuiltinDeserializer instance, but we can't perform the cast during // construction since that makes vtable-based checks fail. Deserializer* const deserializer_; // Stores allocated space for bytecode handlers during eager deserialization. std::vector
* handler_allocations_ = nullptr; // Stores the allocated space for a single handler during lazy // deserialization. Address handler_allocation_ = kNullAddress; bool next_reference_is_weak_ = false; DISALLOW_COPY_AND_ASSIGN(BuiltinDeserializerAllocator) }; } // namespace internal } // namespace v8 #endif // V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_