builtin-serializer.cc 5.31 KB
Newer Older
1 2 3 4 5 6
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/snapshot/builtin-serializer.h"

7
#include "src/interpreter/interpreter.h"
8 9 10 11 12 13
#include "src/objects-inl.h"
#include "src/snapshot/startup-serializer.h"

namespace v8 {
namespace internal {

14 15 16 17
using interpreter::Bytecode;
using interpreter::Bytecodes;
using interpreter::OperandScale;

18 19 20 21 22 23 24 25
BuiltinSerializer::BuiltinSerializer(Isolate* isolate,
                                     StartupSerializer* startup_serializer)
    : Serializer(isolate), startup_serializer_(startup_serializer) {}

BuiltinSerializer::~BuiltinSerializer() {
  OutputStatistics("BuiltinSerializer");
}

26 27 28 29 30 31 32
void BuiltinSerializer::SerializeBuiltinsAndHandlers() {
  // Serialize builtins.

  STATIC_ASSERT(0 == BSU::kFirstBuiltinIndex);

  for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
    SetBuiltinOffset(i, sink_.Position());
33
    SerializeBuiltin(isolate()->builtins()->builtin(i));
34
  }
35 36 37 38 39 40 41

  // Serialize bytecode handlers.

  STATIC_ASSERT(BSU::kNumberOfBuiltins == BSU::kFirstHandlerIndex);

  BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
    SetHandlerOffset(bytecode, operand_scale, sink_.Position());
42
    if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
43 44 45 46 47

    SerializeHandler(
        isolate()->interpreter()->GetBytecodeHandler(bytecode, operand_scale));
  });

48 49 50 51 52 53 54 55 56 57
  STATIC_ASSERT(BSU::kFirstHandlerIndex + BSU::kNumberOfHandlers ==
                BSU::kNumberOfCodeObjects);

  // The DeserializeLazy handlers are serialized by the StartupSerializer
  // during strong root iteration.

  DCHECK(isolate()->heap()->deserialize_lazy_handler()->IsCode());
  DCHECK(isolate()->heap()->deserialize_lazy_handler_wide()->IsCode());
  DCHECK(isolate()->heap()->deserialize_lazy_handler_extra_wide()->IsCode());

58 59
  // Pad with kNop since GetInt() might read too far.
  Pad();
60 61 62

  // Append the offset table. During deserialization, the offset table is
  // extracted by BuiltinSnapshotData.
63 64
  const byte* data = reinterpret_cast<const byte*>(&code_offsets_[0]);
  int data_length = static_cast<int>(sizeof(code_offsets_));
65
  sink_.PutRaw(data, data_length, "BuiltinOffsets");
66 67 68 69
}

void BuiltinSerializer::VisitRootPointers(Root root, Object** start,
                                          Object** end) {
70
  UNREACHABLE();  // We iterate manually in SerializeBuiltins.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
}

void BuiltinSerializer::SerializeBuiltin(Code* code) {
  DCHECK_GE(code->builtin_index(), 0);

  // All builtins are serialized unconditionally when the respective builtin is
  // reached while iterating the builtins list. A builtin seen at any other
  // time (e.g. startup snapshot creation, or while iterating a builtin code
  // object during builtin serialization) is serialized by reference - see
  // BuiltinSerializer::SerializeObject below.
  ObjectSerializer object_serializer(this, code, &sink_, kPlain,
                                     kStartOfObject);
  object_serializer.Serialize();
}

86
void BuiltinSerializer::SerializeHandler(Code* code) {
87
  DCHECK(ObjectIsBytecodeHandler(code));
88 89 90 91 92
  ObjectSerializer object_serializer(this, code, &sink_, kPlain,
                                     kStartOfObject);
  object_serializer.Serialize();
}

93 94 95 96 97
void BuiltinSerializer::SerializeObject(HeapObject* o, HowToCode how_to_code,
                                        WhereToPoint where_to_point, int skip) {
  DCHECK(!o->IsSmi());

  // Roots can simply be serialized as root references.
98
  int root_index = root_index_map()->Lookup(o);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  if (root_index != RootIndexMap::kInvalidRootIndex) {
    DCHECK(startup_serializer_->root_has_been_serialized(root_index));
    PutRoot(root_index, o, how_to_code, where_to_point, skip);
    return;
  }

  // Builtins are serialized using a dedicated bytecode. We only reach this
  // point if encountering a Builtin e.g. while iterating the body of another
  // builtin.
  if (SerializeBuiltinReference(o, how_to_code, where_to_point, skip)) return;

  // Embedded objects are serialized as part of the partial snapshot cache.
  // Currently we expect to see:
  // * Code: Jump targets.
  // * ByteArrays: Relocation infos.
  // * FixedArrays: Handler tables.
  // * Strings: CSA_ASSERTs in debug builds, various other string constants.
  // * HeapNumbers: Embedded constants.
  // TODO(6624): Jump targets should never trigger content serialization, it
  // should always result in a reference instead. Reloc infos and handler
  // tables should not end up in the partial snapshot cache.

  FlushSkip(skip);

  int cache_index = startup_serializer_->PartialSnapshotCacheIndex(o);
  sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
            "PartialSnapshotCache");
  sink_.PutInt(cache_index, "partial_snapshot_cache_index");
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142
void BuiltinSerializer::SetBuiltinOffset(int builtin_id, uint32_t offset) {
  DCHECK(Builtins::IsBuiltinId(builtin_id));
  DCHECK(BSU::IsBuiltinIndex(builtin_id));
  code_offsets_[builtin_id] = offset;
}

void BuiltinSerializer::SetHandlerOffset(Bytecode bytecode,
                                         OperandScale operand_scale,
                                         uint32_t offset) {
  const int index = BSU::BytecodeToIndex(bytecode, operand_scale);
  DCHECK(BSU::IsHandlerIndex(index));
  code_offsets_[index] = offset;
}

143 144
}  // namespace internal
}  // namespace v8