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 #include "src/snapshot/builtin-deserializer-allocator.h" 6 7 #include "src/heap/heap-inl.h" 8 #include "src/interpreter/interpreter.h" 9 #include "src/snapshot/builtin-deserializer.h" 10 #include "src/snapshot/deserializer.h" 11 12 namespace v8 { 13 namespace internal { 14 15 using interpreter::Bytecodes; 16 using interpreter::Interpreter; 17 18 BuiltinDeserializerAllocator::BuiltinDeserializerAllocator( 19 Deserializer<BuiltinDeserializerAllocator>* deserializer) 20 : deserializer_(deserializer) {} 21 22 BuiltinDeserializerAllocator::~BuiltinDeserializerAllocator() { 23 delete handler_allocations_; 24 } 25 26 namespace { 27 int HandlerAllocationIndex(int code_object_id) { 28 return code_object_id - BuiltinSnapshotUtils::kFirstHandlerIndex; 29 } 30 } // namespace 31 32 Address BuiltinDeserializerAllocator::Allocate(AllocationSpace space, 33 int size) { 34 const int code_object_id = deserializer()->CurrentCodeObjectId(); 35 DCHECK_NE(BuiltinDeserializer::kNoCodeObjectId, code_object_id); 36 DCHECK_EQ(CODE_SPACE, space); 37 DCHECK_EQ(deserializer()->ExtractCodeObjectSize(code_object_id), size); 38 #ifdef DEBUG 39 RegisterCodeObjectAllocation(code_object_id); 40 #endif 41 42 if (BSU::IsBuiltinIndex(code_object_id)) { 43 Object* obj = isolate()->builtins()->builtin(code_object_id); 44 DCHECK(Internals::HasHeapObjectTag(obj)); 45 return HeapObject::cast(obj)->address(); 46 } else if (BSU::IsHandlerIndex(code_object_id)) { 47 if (handler_allocation_ != kNullAddress) { 48 // Lazy deserialization. 49 DCHECK_NULL(handler_allocations_); 50 return handler_allocation_; 51 } else { 52 // Eager deserialization. 53 DCHECK_EQ(kNullAddress, handler_allocation_); 54 DCHECK_NOT_NULL(handler_allocations_); 55 int index = HandlerAllocationIndex(code_object_id); 56 DCHECK_NE(kNullAddress, handler_allocations_->at(index)); 57 return handler_allocations_->at(index); 58 } 59 } 60 61 UNREACHABLE(); 62 } 63 64 Heap::Reservation 65 BuiltinDeserializerAllocator::CreateReservationsForEagerBuiltinsAndHandlers() { 66 Heap::Reservation result; 67 68 // Reservations for builtins. 69 70 // DeserializeLazy is always the first builtin reservation (to simplify logic 71 // in InitializeBuiltinsTable). 72 { 73 DCHECK(!Builtins::IsLazy(Builtins::kDeserializeLazy)); 74 uint32_t builtin_size = 75 deserializer()->ExtractCodeObjectSize(Builtins::kDeserializeLazy); 76 DCHECK_LE(builtin_size, MemoryAllocator::PageAreaSize(CODE_SPACE)); 77 result.push_back({builtin_size, kNullAddress, kNullAddress}); 78 } 79 80 for (int i = 0; i < BSU::kNumberOfBuiltins; i++) { 81 if (i == Builtins::kDeserializeLazy) continue; 82 83 // Skip lazy builtins. These will be replaced by the DeserializeLazy code 84 // object in InitializeFromReservations and thus require no reserved space. 85 if (deserializer()->IsLazyDeserializationEnabled() && Builtins::IsLazy(i)) { 86 continue; 87 } 88 89 uint32_t builtin_size = deserializer()->ExtractCodeObjectSize(i); 90 DCHECK_LE(builtin_size, MemoryAllocator::PageAreaSize(CODE_SPACE)); 91 result.push_back({builtin_size, kNullAddress, kNullAddress}); 92 } 93 94 // Reservations for bytecode handlers. 95 96 BSU::ForEachBytecode( 97 [=, &result](Bytecode bytecode, OperandScale operand_scale) { 98 if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) { 99 // Bytecodes without a handler don't require a reservation. 100 return; 101 } else if (FLAG_lazy_handler_deserialization && 102 deserializer()->IsLazyDeserializationEnabled() && 103 Bytecodes::IsLazy(bytecode)) { 104 // Skip lazy handlers. These will be replaced by the DeserializeLazy 105 // code object in InitializeFromReservations and thus require no 106 // reserved space. 107 return; 108 } 109 110 const int index = BSU::BytecodeToIndex(bytecode, operand_scale); 111 uint32_t handler_size = deserializer()->ExtractCodeObjectSize(index); 112 DCHECK_LE(handler_size, MemoryAllocator::PageAreaSize(CODE_SPACE)); 113 result.push_back({handler_size, kNullAddress, kNullAddress}); 114 }); 115 116 return result; 117 } 118 119 void BuiltinDeserializerAllocator::InitializeBuiltinFromReservation( 120 const Heap::Chunk& chunk, int builtin_id) { 121 DCHECK_EQ(deserializer()->ExtractCodeObjectSize(builtin_id), chunk.size); 122 DCHECK_EQ(chunk.size, chunk.end - chunk.start); 123 124 SkipList::Update(chunk.start, chunk.size); 125 isolate()->builtins()->set_builtin(builtin_id, 126 HeapObject::FromAddress(chunk.start)); 127 128 #ifdef DEBUG 129 RegisterCodeObjectReservation(builtin_id); 130 #endif 131 } 132 133 void BuiltinDeserializerAllocator::InitializeHandlerFromReservation( 134 const Heap::Chunk& chunk, interpreter::Bytecode bytecode, 135 interpreter::OperandScale operand_scale) { 136 DCHECK_EQ(deserializer()->ExtractCodeObjectSize( 137 BSU::BytecodeToIndex(bytecode, operand_scale)), 138 chunk.size); 139 DCHECK_EQ(chunk.size, chunk.end - chunk.start); 140 141 SkipList::Update(chunk.start, chunk.size); 142 143 DCHECK_NOT_NULL(handler_allocations_); 144 const int index = 145 HandlerAllocationIndex(BSU::BytecodeToIndex(bytecode, operand_scale)); 146 handler_allocations_->at(index) = chunk.start; 147 148 #ifdef DEBUG 149 RegisterCodeObjectReservation(BSU::BytecodeToIndex(bytecode, operand_scale)); 150 #endif 151 } 152 153 void BuiltinDeserializerAllocator::InitializeFromReservations( 154 const Heap::Reservation& reservation) { 155 DCHECK(!AllowHeapAllocation::IsAllowed()); 156 157 // Initialize the builtins table. 158 159 Builtins* builtins = isolate()->builtins(); 160 int reservation_index = 0; 161 162 // Other builtins can be replaced by DeserializeLazy so it may not be lazy. 163 // It always occupies the first reservation slot. 164 { 165 DCHECK(!Builtins::IsLazy(Builtins::kDeserializeLazy)); 166 InitializeBuiltinFromReservation(reservation[reservation_index], 167 Builtins::kDeserializeLazy); 168 reservation_index++; 169 } 170 171 Code* deserialize_lazy = builtins->builtin(Builtins::kDeserializeLazy); 172 173 for (int i = 0; i < BSU::kNumberOfBuiltins; i++) { 174 if (i == Builtins::kDeserializeLazy) continue; 175 176 if (deserializer()->IsLazyDeserializationEnabled() && Builtins::IsLazy(i)) { 177 builtins->set_builtin(i, deserialize_lazy); 178 } else { 179 InitializeBuiltinFromReservation(reservation[reservation_index], i); 180 reservation_index++; 181 } 182 } 183 184 // Initialize interpreter bytecode handler reservations. 185 186 DCHECK_NULL(handler_allocations_); 187 handler_allocations_ = new std::vector<Address>(BSU::kNumberOfHandlers); 188 189 BSU::ForEachBytecode( 190 [=, &reservation_index](Bytecode bytecode, OperandScale operand_scale) { 191 if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) { 192 // Bytecodes without a handler don't have a reservation. 193 return; 194 } else if (FLAG_lazy_handler_deserialization && 195 deserializer()->IsLazyDeserializationEnabled() && 196 Bytecodes::IsLazy(bytecode)) { 197 // Likewise, bytecodes with lazy handlers don't either. 198 return; 199 } 200 201 InitializeHandlerFromReservation(reservation[reservation_index], 202 bytecode, operand_scale); 203 reservation_index++; 204 }); 205 206 DCHECK_EQ(reservation.size(), reservation_index); 207 } 208 209 void BuiltinDeserializerAllocator::ReserveAndInitializeBuiltinsTableForBuiltin( 210 int builtin_id) { 211 DCHECK(AllowHeapAllocation::IsAllowed()); 212 DCHECK(isolate()->builtins()->is_initialized()); 213 DCHECK(Builtins::IsBuiltinId(builtin_id)); 214 DCHECK_NE(Builtins::kDeserializeLazy, builtin_id); 215 DCHECK_EQ(Builtins::kDeserializeLazy, 216 isolate()->builtins()->builtin(builtin_id)->builtin_index()); 217 218 const uint32_t builtin_size = 219 deserializer()->ExtractCodeObjectSize(builtin_id); 220 DCHECK_LE(builtin_size, MemoryAllocator::PageAreaSize(CODE_SPACE)); 221 222 Handle<HeapObject> o = 223 isolate()->factory()->NewCodeForDeserialization(builtin_size); 224 225 // Note: After this point and until deserialization finishes, heap allocation 226 // is disallowed. We currently can't safely assert this since we'd need to 227 // pass the DisallowHeapAllocation scope out of this function. 228 229 // Write the allocated filler object into the builtins table. It will be 230 // returned by our custom Allocate method below once needed. 231 232 isolate()->builtins()->set_builtin(builtin_id, *o); 233 234 #ifdef DEBUG 235 RegisterCodeObjectReservation(builtin_id); 236 #endif 237 } 238 239 void BuiltinDeserializerAllocator::ReserveForHandler( 240 Bytecode bytecode, OperandScale operand_scale) { 241 DCHECK(AllowHeapAllocation::IsAllowed()); 242 DCHECK(isolate()->interpreter()->IsDispatchTableInitialized()); 243 244 const int code_object_id = BSU::BytecodeToIndex(bytecode, operand_scale); 245 const uint32_t handler_size = 246 deserializer()->ExtractCodeObjectSize(code_object_id); 247 DCHECK_LE(handler_size, MemoryAllocator::PageAreaSize(CODE_SPACE)); 248 249 handler_allocation_ = 250 isolate()->factory()->NewCodeForDeserialization(handler_size)->address(); 251 252 // Note: After this point and until deserialization finishes, heap allocation 253 // is disallowed. We currently can't safely assert this since we'd need to 254 // pass the DisallowHeapAllocation scope out of this function. 255 256 #ifdef DEBUG 257 RegisterCodeObjectReservation(code_object_id); 258 #endif 259 } 260 261 #ifdef DEBUG 262 void BuiltinDeserializerAllocator::RegisterCodeObjectReservation( 263 int code_object_id) { 264 const auto result = unused_reservations_.emplace(code_object_id); 265 CHECK(result.second); // False, iff builtin_id was already present in set. 266 } 267 268 void BuiltinDeserializerAllocator::RegisterCodeObjectAllocation( 269 int code_object_id) { 270 const size_t removed_elems = unused_reservations_.erase(code_object_id); 271 CHECK_EQ(removed_elems, 1); 272 } 273 274 bool BuiltinDeserializerAllocator::ReservationsAreFullyUsed() const { 275 // Not 100% precise but should be good enough. 276 return unused_reservations_.empty(); 277 } 278 #endif // DEBUG 279 280 Isolate* BuiltinDeserializerAllocator::isolate() const { 281 return deserializer()->isolate(); 282 } 283 284 BuiltinDeserializer* BuiltinDeserializerAllocator::deserializer() const { 285 return static_cast<BuiltinDeserializer*>(deserializer_); 286 } 287 288 } // namespace internal 289 } // namespace v8 290