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.h"
      6 
      7 #include "src/assembler-inl.h"
      8 #include "src/interpreter/interpreter.h"
      9 #include "src/objects-inl.h"
     10 #include "src/snapshot/snapshot.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 using interpreter::Bytecodes;
     16 using interpreter::Interpreter;
     17 
     18 // Tracks the code object currently being deserialized (required for
     19 // allocation).
     20 class DeserializingCodeObjectScope {
     21  public:
     22   DeserializingCodeObjectScope(BuiltinDeserializer* builtin_deserializer,
     23                                int code_object_id)
     24       : builtin_deserializer_(builtin_deserializer) {
     25     DCHECK_EQ(BuiltinDeserializer::kNoCodeObjectId,
     26               builtin_deserializer->current_code_object_id_);
     27     builtin_deserializer->current_code_object_id_ = code_object_id;
     28   }
     29 
     30   ~DeserializingCodeObjectScope() {
     31     builtin_deserializer_->current_code_object_id_ =
     32         BuiltinDeserializer::kNoCodeObjectId;
     33   }
     34 
     35  private:
     36   BuiltinDeserializer* builtin_deserializer_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(DeserializingCodeObjectScope)
     39 };
     40 
     41 BuiltinDeserializer::BuiltinDeserializer(Isolate* isolate,
     42                                          const BuiltinSnapshotData* data)
     43     : Deserializer(data, false) {
     44   code_offsets_ = data->BuiltinOffsets();
     45   DCHECK_EQ(BSU::kNumberOfCodeObjects, code_offsets_.length());
     46   DCHECK(std::is_sorted(code_offsets_.begin(), code_offsets_.end()));
     47 
     48   Initialize(isolate);
     49 }
     50 
     51 void BuiltinDeserializer::DeserializeEagerBuiltinsAndHandlers() {
     52   DCHECK(!AllowHeapAllocation::IsAllowed());
     53   DCHECK_EQ(0, source()->position());
     54 
     55   // Deserialize builtins.
     56 
     57   Builtins* builtins = isolate()->builtins();
     58   for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
     59     if (IsLazyDeserializationEnabled() && Builtins::IsLazy(i)) {
     60       // Do nothing. These builtins have been replaced by DeserializeLazy in
     61       // InitializeFromReservations.
     62       DCHECK_EQ(builtins->builtin(Builtins::kDeserializeLazy),
     63                 builtins->builtin(i));
     64     } else {
     65       builtins->set_builtin(i, DeserializeBuiltinRaw(i));
     66     }
     67   }
     68 
     69 #ifdef DEBUG
     70   for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
     71     Object* o = builtins->builtin(i);
     72     DCHECK(o->IsCode() && Code::cast(o)->is_builtin());
     73   }
     74 #endif
     75 
     76 #ifdef ENABLE_DISASSEMBLER
     77   if (FLAG_print_builtin_code) {
     78     // We can't print builtins during deserialization because they may refer
     79     // to not yet deserialized builtins.
     80     for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
     81       if (!IsLazyDeserializationEnabled() || !Builtins::IsLazy(i)) {
     82         Code* code = builtins->builtin(i);
     83         const char* name = Builtins::name(i);
     84         code->PrintBuiltinCode(isolate(), name);
     85       }
     86     }
     87   }
     88 #endif
     89 
     90   // Deserialize bytecode handlers.
     91 
     92   Interpreter* interpreter = isolate()->interpreter();
     93   DCHECK(!isolate()->interpreter()->IsDispatchTableInitialized());
     94 
     95   BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
     96     // Bytecodes without a dedicated handler are patched up in a second pass.
     97     if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
     98 
     99     // If lazy-deserialization is enabled and the current bytecode is lazy,
    100     // we write the generic LazyDeserialization handler into the dispatch table
    101     // and deserialize later upon first use.
    102     Code* code = (FLAG_lazy_handler_deserialization &&
    103                   IsLazyDeserializationEnabled() && Bytecodes::IsLazy(bytecode))
    104                      ? GetDeserializeLazyHandler(operand_scale)
    105                      : DeserializeHandlerRaw(bytecode, operand_scale);
    106 
    107     interpreter->SetBytecodeHandler(bytecode, operand_scale, code);
    108   });
    109 
    110   // Patch up holes in the dispatch table.
    111 
    112   Code* illegal_handler = interpreter->GetBytecodeHandler(
    113       Bytecode::kIllegal, OperandScale::kSingle);
    114 
    115   BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
    116     if (Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
    117     interpreter->SetBytecodeHandler(bytecode, operand_scale, illegal_handler);
    118   });
    119 
    120   DCHECK(isolate()->interpreter()->IsDispatchTableInitialized());
    121 }
    122 
    123 Code* BuiltinDeserializer::DeserializeBuiltin(int builtin_id) {
    124   allocator()->ReserveAndInitializeBuiltinsTableForBuiltin(builtin_id);
    125   DisallowHeapAllocation no_gc;
    126   Code* code = DeserializeBuiltinRaw(builtin_id);
    127 
    128 #ifdef ENABLE_DISASSEMBLER
    129   if (FLAG_print_builtin_code) {
    130     const char* name = Builtins::name(builtin_id);
    131     code->PrintBuiltinCode(isolate(), name);
    132   }
    133 #endif  // ENABLE_DISASSEMBLER
    134 
    135   return code;
    136 }
    137 
    138 Code* BuiltinDeserializer::DeserializeHandler(Bytecode bytecode,
    139                                               OperandScale operand_scale) {
    140   allocator()->ReserveForHandler(bytecode, operand_scale);
    141   DisallowHeapAllocation no_gc;
    142   return DeserializeHandlerRaw(bytecode, operand_scale);
    143 }
    144 
    145 Code* BuiltinDeserializer::DeserializeBuiltinRaw(int builtin_id) {
    146   DCHECK(!AllowHeapAllocation::IsAllowed());
    147   DCHECK(Builtins::IsBuiltinId(builtin_id));
    148 
    149   DeserializingCodeObjectScope scope(this, builtin_id);
    150 
    151   const int initial_position = source()->position();
    152   source()->set_position(code_offsets_[builtin_id]);
    153 
    154   Object* o = ReadDataSingle();
    155   DCHECK(o->IsCode() && Code::cast(o)->is_builtin());
    156 
    157   // Rewind.
    158   source()->set_position(initial_position);
    159 
    160   // Flush the instruction cache.
    161   Code* code = Code::cast(o);
    162   Assembler::FlushICache(code->raw_instruction_start(),
    163                          code->raw_instruction_size());
    164 
    165   PROFILE(isolate(), CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
    166                                      AbstractCode::cast(code),
    167                                      Builtins::name(builtin_id)));
    168   LOG_CODE_EVENT(isolate(),
    169                  CodeLinePosInfoRecordEvent(
    170                      code->raw_instruction_start(),
    171                      ByteArray::cast(code->source_position_table())));
    172   return code;
    173 }
    174 
    175 Code* BuiltinDeserializer::DeserializeHandlerRaw(Bytecode bytecode,
    176                                                  OperandScale operand_scale) {
    177   DCHECK(!AllowHeapAllocation::IsAllowed());
    178   DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
    179 
    180   const int code_object_id = BSU::BytecodeToIndex(bytecode, operand_scale);
    181   DeserializingCodeObjectScope scope(this, code_object_id);
    182 
    183   const int initial_position = source()->position();
    184   source()->set_position(code_offsets_[code_object_id]);
    185 
    186   Object* o = ReadDataSingle();
    187   DCHECK(o->IsCode() && Code::cast(o)->kind() == Code::BYTECODE_HANDLER);
    188 
    189   // Rewind.
    190   source()->set_position(initial_position);
    191 
    192   // Flush the instruction cache.
    193   Code* code = Code::cast(o);
    194   Assembler::FlushICache(code->raw_instruction_start(),
    195                          code->raw_instruction_size());
    196 
    197   std::string name = Bytecodes::ToString(bytecode, operand_scale);
    198   PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
    199                                      AbstractCode::cast(code), name.c_str()));
    200 #ifdef ENABLE_DISASSEMBLER
    201   if (FLAG_print_builtin_code) {
    202     code->PrintBuiltinCode(isolate(), name.c_str());
    203   }
    204 #endif  // ENABLE_DISASSEMBLER
    205 
    206   return code;
    207 }
    208 
    209 uint32_t BuiltinDeserializer::ExtractCodeObjectSize(int code_object_id) {
    210   DCHECK_LT(code_object_id, BSU::kNumberOfCodeObjects);
    211 
    212   const int initial_position = source()->position();
    213 
    214   // Grab the size of the code object.
    215   source()->set_position(code_offsets_[code_object_id]);
    216   byte data = source()->Get();
    217 
    218   USE(data);
    219   DCHECK_EQ(kNewObject | kPlain | kStartOfObject | CODE_SPACE, data);
    220   const uint32_t result = source()->GetInt() << kObjectAlignmentBits;
    221 
    222   // Rewind.
    223   source()->set_position(initial_position);
    224 
    225   return result;
    226 }
    227 
    228 Code* BuiltinDeserializer::GetDeserializeLazyHandler(
    229     interpreter::OperandScale operand_scale) const {
    230   STATIC_ASSERT(interpreter::BytecodeOperands::kOperandScaleCount == 3);
    231   switch (operand_scale) {
    232     case OperandScale::kSingle:
    233       return Code::cast(isolate()->heap()->deserialize_lazy_handler());
    234     case OperandScale::kDouble:
    235       return Code::cast(isolate()->heap()->deserialize_lazy_handler_wide());
    236     case OperandScale::kQuadruple:
    237       return Code::cast(
    238           isolate()->heap()->deserialize_lazy_handler_extra_wide());
    239   }
    240   UNREACHABLE();
    241 }
    242 
    243 }  // namespace internal
    244 }  // namespace v8
    245