summaryrefslogtreecommitdiff
path: root/deps/v8/src/snapshot/builtin-serializer.cc
blob: 893c79c05e6358d5aea44612c785a018f41b18fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 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"

#include "src/interpreter/interpreter.h"
#include "src/objects-inl.h"
#include "src/snapshot/startup-serializer.h"

namespace v8 {
namespace internal {

using interpreter::Bytecode;
using interpreter::Bytecodes;
using interpreter::OperandScale;

BuiltinSerializer::BuiltinSerializer(Isolate* isolate,
                                     StartupSerializer* startup_serializer)
    : Serializer(isolate), startup_serializer_(startup_serializer) {}

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

void BuiltinSerializer::SerializeBuiltinsAndHandlers() {
  // Serialize builtins.

  STATIC_ASSERT(0 == BSU::kFirstBuiltinIndex);

  for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
    SetBuiltinOffset(i, sink_.Position());
    SerializeBuiltin(isolate()->builtins()->builtin(i));
  }

  // Serialize bytecode handlers.

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

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

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

  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());

  // Pad with kNop since GetInt() might read too far.
  Pad();

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

void BuiltinSerializer::VisitRootPointers(Root root, Object** start,
                                          Object** end) {
  UNREACHABLE();  // We iterate manually in SerializeBuiltins.
}

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();
}

void BuiltinSerializer::SerializeHandler(Code* code) {
  DCHECK(ObjectIsBytecodeHandler(code));
  ObjectSerializer object_serializer(this, code, &sink_, kPlain,
                                     kStartOfObject);
  object_serializer.Serialize();
}

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.
  int root_index = root_index_map()->Lookup(o);
  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");
}

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;
}

}  // namespace internal
}  // namespace v8