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-deserializer.h"
6
7 #include "src/assembler-inl.h"
8 #include "src/interpreter/interpreter.h"
9 #include "src/objects-inl.h"
10 #include "src/snapshot/snapshot.h"
11
12 namespace v8 {
13 namespace internal {
14
15 using interpreter::Bytecodes;
16 using interpreter::Interpreter;
17
18 // Tracks the code object currently being deserialized (required for
19 // allocation).
20 class DeserializingCodeObjectScope {
21 public:
DeserializingCodeObjectScope(BuiltinDeserializer * builtin_deserializer,int code_object_id)22 DeserializingCodeObjectScope(BuiltinDeserializer* builtin_deserializer,
23 int code_object_id)
24 : builtin_deserializer_(builtin_deserializer) {
25 DCHECK_EQ(BuiltinDeserializer::kNoCodeObjectId,
26 builtin_deserializer->current_code_object_id_);
27 builtin_deserializer->current_code_object_id_ = code_object_id;
28 }
29
~DeserializingCodeObjectScope()30 ~DeserializingCodeObjectScope() {
31 builtin_deserializer_->current_code_object_id_ =
32 BuiltinDeserializer::kNoCodeObjectId;
33 }
34
35 private:
36 BuiltinDeserializer* builtin_deserializer_;
37
38 DISALLOW_COPY_AND_ASSIGN(DeserializingCodeObjectScope)
39 };
40
BuiltinDeserializer(Isolate * isolate,const BuiltinSnapshotData * data)41 BuiltinDeserializer::BuiltinDeserializer(Isolate* isolate,
42 const BuiltinSnapshotData* data)
43 : Deserializer(data, false) {
44 code_offsets_ = data->BuiltinOffsets();
45 DCHECK_EQ(BSU::kNumberOfCodeObjects, code_offsets_.length());
46 DCHECK(std::is_sorted(code_offsets_.begin(), code_offsets_.end()));
47
48 Initialize(isolate);
49 }
50
DeserializeEagerBuiltinsAndHandlers()51 void BuiltinDeserializer::DeserializeEagerBuiltinsAndHandlers() {
52 DCHECK(!AllowHeapAllocation::IsAllowed());
53 DCHECK_EQ(0, source()->position());
54
55 // Deserialize builtins.
56
57 Builtins* builtins = isolate()->builtins();
58 for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
59 if (IsLazyDeserializationEnabled() && Builtins::IsLazy(i)) {
60 // Do nothing. These builtins have been replaced by DeserializeLazy in
61 // InitializeFromReservations.
62 DCHECK_EQ(builtins->builtin(Builtins::kDeserializeLazy),
63 builtins->builtin(i));
64 } else {
65 builtins->set_builtin(i, DeserializeBuiltinRaw(i));
66 }
67 }
68
69 #ifdef DEBUG
70 for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
71 Object* o = builtins->builtin(i);
72 DCHECK(o->IsCode() && Code::cast(o)->is_builtin());
73 }
74 #endif
75
76 #ifdef ENABLE_DISASSEMBLER
77 if (FLAG_print_builtin_code) {
78 // We can't print builtins during deserialization because they may refer
79 // to not yet deserialized builtins.
80 for (int i = 0; i < BSU::kNumberOfBuiltins; i++) {
81 if (!IsLazyDeserializationEnabled() || !Builtins::IsLazy(i)) {
82 Code* code = builtins->builtin(i);
83 const char* name = Builtins::name(i);
84 code->PrintBuiltinCode(isolate(), name);
85 }
86 }
87 }
88 #endif
89
90 // Deserialize bytecode handlers.
91
92 Interpreter* interpreter = isolate()->interpreter();
93 DCHECK(!isolate()->interpreter()->IsDispatchTableInitialized());
94
95 BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
96 // Bytecodes without a dedicated handler are patched up in a second pass.
97 if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
98
99 // If lazy-deserialization is enabled and the current bytecode is lazy,
100 // we write the generic LazyDeserialization handler into the dispatch table
101 // and deserialize later upon first use.
102 Code* code = (FLAG_lazy_handler_deserialization &&
103 IsLazyDeserializationEnabled() && Bytecodes::IsLazy(bytecode))
104 ? GetDeserializeLazyHandler(operand_scale)
105 : DeserializeHandlerRaw(bytecode, operand_scale);
106
107 interpreter->SetBytecodeHandler(bytecode, operand_scale, code);
108 });
109
110 // Patch up holes in the dispatch table.
111
112 Code* illegal_handler = interpreter->GetBytecodeHandler(
113 Bytecode::kIllegal, OperandScale::kSingle);
114
115 BSU::ForEachBytecode([=](Bytecode bytecode, OperandScale operand_scale) {
116 if (Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return;
117 interpreter->SetBytecodeHandler(bytecode, operand_scale, illegal_handler);
118 });
119
120 DCHECK(isolate()->interpreter()->IsDispatchTableInitialized());
121 }
122
DeserializeBuiltin(int builtin_id)123 Code* BuiltinDeserializer::DeserializeBuiltin(int builtin_id) {
124 allocator()->ReserveAndInitializeBuiltinsTableForBuiltin(builtin_id);
125 DisallowHeapAllocation no_gc;
126 Code* code = DeserializeBuiltinRaw(builtin_id);
127
128 #ifdef ENABLE_DISASSEMBLER
129 if (FLAG_print_builtin_code) {
130 const char* name = Builtins::name(builtin_id);
131 code->PrintBuiltinCode(isolate(), name);
132 }
133 #endif // ENABLE_DISASSEMBLER
134
135 return code;
136 }
137
DeserializeHandler(Bytecode bytecode,OperandScale operand_scale)138 Code* BuiltinDeserializer::DeserializeHandler(Bytecode bytecode,
139 OperandScale operand_scale) {
140 allocator()->ReserveForHandler(bytecode, operand_scale);
141 DisallowHeapAllocation no_gc;
142 return DeserializeHandlerRaw(bytecode, operand_scale);
143 }
144
DeserializeBuiltinRaw(int builtin_id)145 Code* BuiltinDeserializer::DeserializeBuiltinRaw(int builtin_id) {
146 DCHECK(!AllowHeapAllocation::IsAllowed());
147 DCHECK(Builtins::IsBuiltinId(builtin_id));
148
149 DeserializingCodeObjectScope scope(this, builtin_id);
150
151 const int initial_position = source()->position();
152 source()->set_position(code_offsets_[builtin_id]);
153
154 Object* o = ReadDataSingle();
155 DCHECK(o->IsCode() && Code::cast(o)->is_builtin());
156
157 // Rewind.
158 source()->set_position(initial_position);
159
160 // Flush the instruction cache.
161 Code* code = Code::cast(o);
162 Assembler::FlushICache(code->raw_instruction_start(),
163 code->raw_instruction_size());
164
165 PROFILE(isolate(), CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
166 AbstractCode::cast(code),
167 Builtins::name(builtin_id)));
168 LOG_CODE_EVENT(isolate(),
169 CodeLinePosInfoRecordEvent(
170 code->raw_instruction_start(),
171 ByteArray::cast(code->source_position_table())));
172 return code;
173 }
174
DeserializeHandlerRaw(Bytecode bytecode,OperandScale operand_scale)175 Code* BuiltinDeserializer::DeserializeHandlerRaw(Bytecode bytecode,
176 OperandScale operand_scale) {
177 DCHECK(!AllowHeapAllocation::IsAllowed());
178 DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
179
180 const int code_object_id = BSU::BytecodeToIndex(bytecode, operand_scale);
181 DeserializingCodeObjectScope scope(this, code_object_id);
182
183 const int initial_position = source()->position();
184 source()->set_position(code_offsets_[code_object_id]);
185
186 Object* o = ReadDataSingle();
187 DCHECK(o->IsCode() && Code::cast(o)->kind() == Code::BYTECODE_HANDLER);
188
189 // Rewind.
190 source()->set_position(initial_position);
191
192 // Flush the instruction cache.
193 Code* code = Code::cast(o);
194 Assembler::FlushICache(code->raw_instruction_start(),
195 code->raw_instruction_size());
196
197 std::string name = Bytecodes::ToString(bytecode, operand_scale);
198 PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
199 AbstractCode::cast(code), name.c_str()));
200 #ifdef ENABLE_DISASSEMBLER
201 if (FLAG_print_builtin_code) {
202 code->PrintBuiltinCode(isolate(), name.c_str());
203 }
204 #endif // ENABLE_DISASSEMBLER
205
206 return code;
207 }
208
ExtractCodeObjectSize(int code_object_id)209 uint32_t BuiltinDeserializer::ExtractCodeObjectSize(int code_object_id) {
210 DCHECK_LT(code_object_id, BSU::kNumberOfCodeObjects);
211
212 const int initial_position = source()->position();
213
214 // Grab the size of the code object.
215 source()->set_position(code_offsets_[code_object_id]);
216 byte data = source()->Get();
217
218 USE(data);
219 DCHECK_EQ(kNewObject | kPlain | kStartOfObject | CODE_SPACE, data);
220 const uint32_t result = source()->GetInt() << kObjectAlignmentBits;
221
222 // Rewind.
223 source()->set_position(initial_position);
224
225 return result;
226 }
227
GetDeserializeLazyHandler(interpreter::OperandScale operand_scale) const228 Code* BuiltinDeserializer::GetDeserializeLazyHandler(
229 interpreter::OperandScale operand_scale) const {
230 STATIC_ASSERT(interpreter::BytecodeOperands::kOperandScaleCount == 3);
231 switch (operand_scale) {
232 case OperandScale::kSingle:
233 return Code::cast(isolate()->heap()->deserialize_lazy_handler());
234 case OperandScale::kDouble:
235 return Code::cast(isolate()->heap()->deserialize_lazy_handler_wide());
236 case OperandScale::kQuadruple:
237 return Code::cast(
238 isolate()->heap()->deserialize_lazy_handler_extra_wide());
239 }
240 UNREACHABLE();
241 }
242
243 } // namespace internal
244 } // namespace v8
245