1 // Copyright 2017 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_ 6 #define V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_ 7 8 #include <unordered_set> 9 10 #include "src/globals.h" 11 #include "src/heap/heap.h" 12 #include "src/interpreter/interpreter.h" 13 #include "src/snapshot/serializer-common.h" 14 15 namespace v8 { 16 namespace internal { 17 18 template <class AllocatorT> 19 class Deserializer; 20 21 class BuiltinDeserializer; 22 class BuiltinSnapshotUtils; 23 24 class BuiltinDeserializerAllocator final { 25 using BSU = BuiltinSnapshotUtils; 26 using Bytecode = interpreter::Bytecode; 27 using OperandScale = interpreter::OperandScale; 28 29 public: 30 BuiltinDeserializerAllocator( 31 Deserializer<BuiltinDeserializerAllocator>* deserializer); 32 33 ~BuiltinDeserializerAllocator(); 34 35 // ------- Allocation Methods ------- 36 // Methods related to memory allocation during deserialization. 37 38 // Allocation works differently here than in other deserializers. Instead of 39 // a statically-known memory area determined at serialization-time, our 40 // memory requirements here are determined at runtime. Another major 41 // difference is that we create builtin Code objects up-front (before 42 // deserialization) in order to avoid having to patch builtin references 43 // later on. See also the kBuiltin case in deserializer.cc. 44 // 45 // There are three ways that we use to reserve / allocate space. In all 46 // cases, required objects are requested from the GC prior to 47 // deserialization. 1. pre-allocated builtin code objects are written into 48 // the builtins table (this is to make deserialization of builtin references 49 // easier). Pre-allocated handler code objects are 2. stored in the 50 // {handler_allocations_} vector (at eager-deserialization time) and 3. 51 // stored in {handler_allocation_} (at lazy-deserialization time). 52 // 53 // Allocate simply returns the pre-allocated object prepared by 54 // InitializeFromReservations. 55 Address Allocate(AllocationSpace space, int size); 56 MoveToNextChunk(AllocationSpace space)57 void MoveToNextChunk(AllocationSpace space) { UNREACHABLE(); } SetAlignment(AllocationAlignment alignment)58 void SetAlignment(AllocationAlignment alignment) { UNREACHABLE(); } 59 set_next_reference_is_weak(bool next_reference_is_weak)60 void set_next_reference_is_weak(bool next_reference_is_weak) { 61 next_reference_is_weak_ = next_reference_is_weak; 62 } 63 GetAndClearNextReferenceIsWeak()64 bool GetAndClearNextReferenceIsWeak() { 65 bool saved = next_reference_is_weak_; 66 next_reference_is_weak_ = false; 67 return saved; 68 } 69 70 #ifdef DEBUG next_reference_is_weak()71 bool next_reference_is_weak() const { return next_reference_is_weak_; } 72 #endif 73 GetMap(uint32_t index)74 HeapObject* GetMap(uint32_t index) { UNREACHABLE(); } GetLargeObject(uint32_t index)75 HeapObject* GetLargeObject(uint32_t index) { UNREACHABLE(); } GetObject(AllocationSpace space,uint32_t chunk_index,uint32_t chunk_offset)76 HeapObject* GetObject(AllocationSpace space, uint32_t chunk_index, 77 uint32_t chunk_offset) { 78 UNREACHABLE(); 79 } 80 81 // ------- Reservation Methods ------- 82 // Methods related to memory reservations (prior to deserialization). 83 84 // Builtin deserialization does not bake reservations into the snapshot, hence 85 // this is a nop. DecodeReservation(std::vector<SerializedData::Reservation> res)86 void DecodeReservation(std::vector<SerializedData::Reservation> res) {} 87 88 // These methods are used to pre-allocate builtin objects prior to 89 // deserialization. 90 // TODO(jgruber): Refactor reservation/allocation logic in deserializers to 91 // make this less messy. 92 Heap::Reservation CreateReservationsForEagerBuiltinsAndHandlers(); 93 void InitializeFromReservations(const Heap::Reservation& reservation); 94 95 // Creates reservations and initializes the builtins table in preparation for 96 // lazily deserializing a single builtin. 97 void ReserveAndInitializeBuiltinsTableForBuiltin(int builtin_id); 98 99 // Pre-allocates a code object preparation for lazily deserializing a single 100 // handler. 101 void ReserveForHandler(Bytecode bytecode, OperandScale operand_scale); 102 103 #ifdef DEBUG 104 bool ReservationsAreFullyUsed() const; 105 #endif 106 107 private: 108 Isolate* isolate() const; 109 BuiltinDeserializer* deserializer() const; 110 111 // Used after memory allocation prior to isolate initialization, to register 112 // the newly created object in code space and add it to the builtins table. 113 void InitializeBuiltinFromReservation(const Heap::Chunk& chunk, 114 int builtin_id); 115 116 // As above, but for interpreter bytecode handlers. 117 void InitializeHandlerFromReservation( 118 const Heap::Chunk& chunk, interpreter::Bytecode bytecode, 119 interpreter::OperandScale operand_scale); 120 121 #ifdef DEBUG 122 void RegisterCodeObjectReservation(int code_object_id); 123 void RegisterCodeObjectAllocation(int code_object_id); 124 std::unordered_set<int> unused_reservations_; 125 #endif 126 127 private: 128 // The current deserializer. Note that this always points to a 129 // BuiltinDeserializer instance, but we can't perform the cast during 130 // construction since that makes vtable-based checks fail. 131 Deserializer<BuiltinDeserializerAllocator>* const deserializer_; 132 133 // Stores allocated space for bytecode handlers during eager deserialization. 134 std::vector<Address>* handler_allocations_ = nullptr; 135 136 // Stores the allocated space for a single handler during lazy 137 // deserialization. 138 Address handler_allocation_ = kNullAddress; 139 140 bool next_reference_is_weak_ = false; 141 142 DISALLOW_COPY_AND_ASSIGN(BuiltinDeserializerAllocator) 143 }; 144 145 } // namespace internal 146 } // namespace v8 147 148 #endif // V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_ 149