Home | History | Annotate | Download | only in snapshot
      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