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-serializer.h"
      6 
      7 #include "src/interpreter/interpreter.h"
      8 #include "src/objects-inl.h"
      9 #include "src/snapshot/startup-serializer.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 using interpreter::Bytecode;
     15 using interpreter::Bytecodes;
     16 using interpreter::OperandScale;
     17 
     18 BuiltinSerializer::BuiltinSerializer(Isolate* isolate,
     19                                      StartupSerializer* startup_serializer)
     20     : Serializer(isolate), startup_serializer_(startup_serializer) {}
     21 
     22 BuiltinSerializer::~BuiltinSerializer() {
     23   OutputStatistics("BuiltinSerializer");
     24 }
     25 
     26 void BuiltinSerializer::SerializeBuiltinsAndHandlers() {
     27   // Serialize builtins.
     28 
     29   STATIC_ASSERT(0 == BSU::kFirstBuiltinIndex);
     30 
     31   for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
     32     SetBuiltinOffset(i, sink_.Position());
     33     SerializeBuiltin(isolate()->builtins()->builtin(i));
     34   }
     35 
     36   // Serialize bytecode handlers.
     37 
     38   STATIC_ASSERT(BSU::kNumberOfBuiltins == BSU::kFirstHandlerIndex);
     39 
     40   BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
     41     SetHandlerOffset(bytecode, operand_scale, sink_.Position());
     42     if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
     43 
     44     SerializeHandler(
     45         isolate()->interpreter()->GetBytecodeHandler(bytecode, operand_scale));
     46   });
     47 
     48   STATIC_ASSERT(BSU::kFirstHandlerIndex + BSU::kNumberOfHandlers ==
     49                 BSU::kNumberOfCodeObjects);
     50 
     51   // The DeserializeLazy handlers are serialized by the StartupSerializer
     52   // during strong root iteration.
     53 
     54   DCHECK(isolate()->heap()->deserialize_lazy_handler()->IsCode());
     55   DCHECK(isolate()->heap()->deserialize_lazy_handler_wide()->IsCode());
     56   DCHECK(isolate()->heap()->deserialize_lazy_handler_extra_wide()->IsCode());
     57 
     58   // Pad with kNop since GetInt() might read too far.
     59   Pad();
     60 
     61   // Append the offset table. During deserialization, the offset table is
     62   // extracted by BuiltinSnapshotData.
     63   const byte* data = reinterpret_cast<const byte*>(&code_offsets_[0]);
     64   int data_length = static_cast<int>(sizeof(code_offsets_));
     65   sink_.PutRaw(data, data_length, "BuiltinOffsets");
     66 }
     67 
     68 void BuiltinSerializer::VisitRootPointers(Root root, const char* description,
     69                                           Object** start, Object** end) {
     70   UNREACHABLE();  // We iterate manually in SerializeBuiltins.
     71 }
     72 
     73 void BuiltinSerializer::SerializeBuiltin(Code* code) {
     74   DCHECK_GE(code->builtin_index(), 0);
     75 
     76   // All builtins are serialized unconditionally when the respective builtin is
     77   // reached while iterating the builtins list. A builtin seen at any other
     78   // time (e.g. startup snapshot creation, or while iterating a builtin code
     79   // object during builtin serialization) is serialized by reference - see
     80   // BuiltinSerializer::SerializeObject below.
     81   ObjectSerializer object_serializer(this, code, &sink_, kPlain,
     82                                      kStartOfObject);
     83   object_serializer.Serialize();
     84 }
     85 
     86 void BuiltinSerializer::SerializeHandler(Code* code) {
     87   DCHECK(ObjectIsBytecodeHandler(code));
     88   ObjectSerializer object_serializer(this, code, &sink_, kPlain,
     89                                      kStartOfObject);
     90   object_serializer.Serialize();
     91 }
     92 
     93 void BuiltinSerializer::SerializeObject(HeapObject* o, HowToCode how_to_code,
     94                                         WhereToPoint where_to_point, int skip) {
     95   DCHECK(!o->IsSmi());
     96 
     97   // Roots can simply be serialized as root references.
     98   int root_index = root_index_map()->Lookup(o);
     99   if (root_index != RootIndexMap::kInvalidRootIndex) {
    100     DCHECK(startup_serializer_->root_has_been_serialized(root_index));
    101     PutRoot(root_index, o, how_to_code, where_to_point, skip);
    102     return;
    103   }
    104 
    105   // Builtins are serialized using a dedicated bytecode. We only reach this
    106   // point if encountering a Builtin e.g. while iterating the body of another
    107   // builtin.
    108   if (SerializeBuiltinReference(o, how_to_code, where_to_point, skip)) return;
    109 
    110   // Embedded objects are serialized as part of the partial snapshot cache.
    111   // Currently we expect to see:
    112   // * Code: Jump targets.
    113   // * ByteArrays: Relocation infos.
    114   // * FixedArrays: Handler tables.
    115   // * Strings: CSA_ASSERTs in debug builds, various other string constants.
    116   // * HeapNumbers: Embedded constants.
    117   // TODO(6624): Jump targets should never trigger content serialization, it
    118   // should always result in a reference instead. Reloc infos and handler
    119   // tables should not end up in the partial snapshot cache.
    120 
    121   FlushSkip(skip);
    122 
    123   int cache_index = startup_serializer_->PartialSnapshotCacheIndex(o);
    124   sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
    125             "PartialSnapshotCache");
    126   sink_.PutInt(cache_index, "partial_snapshot_cache_index");
    127 }
    128 
    129 void BuiltinSerializer::SetBuiltinOffset(int builtin_id, uint32_t offset) {
    130   DCHECK(Builtins::IsBuiltinId(builtin_id));
    131   DCHECK(BSU::IsBuiltinIndex(builtin_id));
    132   code_offsets_[builtin_id] = offset;
    133 }
    134 
    135 void BuiltinSerializer::SetHandlerOffset(Bytecode bytecode,
    136                                          OperandScale operand_scale,
    137                                          uint32_t offset) {
    138   const int index = BSU::BytecodeToIndex(bytecode, operand_scale);
    139   DCHECK(BSU::IsHandlerIndex(index));
    140   code_offsets_[index] = offset;
    141 }
    142 
    143 }  // namespace internal
    144 }  // namespace v8
    145