• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BuiltinSerializer(Isolate * isolate,StartupSerializer * startup_serializer)18 BuiltinSerializer::BuiltinSerializer(Isolate* isolate,
19                                      StartupSerializer* startup_serializer)
20     : Serializer(isolate), startup_serializer_(startup_serializer) {}
21 
~BuiltinSerializer()22 BuiltinSerializer::~BuiltinSerializer() {
23   OutputStatistics("BuiltinSerializer");
24 }
25 
SerializeBuiltinsAndHandlers()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 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)68 void BuiltinSerializer::VisitRootPointers(Root root, const char* description,
69                                           Object** start, Object** end) {
70   UNREACHABLE();  // We iterate manually in SerializeBuiltins.
71 }
72 
SerializeBuiltin(Code * code)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 
SerializeHandler(Code * code)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 
SerializeObject(HeapObject * o,HowToCode how_to_code,WhereToPoint where_to_point,int skip)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 
SetBuiltinOffset(int builtin_id,uint32_t offset)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 
SetHandlerOffset(Bytecode bytecode,OperandScale operand_scale,uint32_t offset)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