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