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: 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 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 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 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 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 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 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 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 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 228 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