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