1 // Copyright 2018 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 #ifndef V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_ 6 #define V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_ 7 8 #include "src/base/macros.h" 9 #include "src/builtins/builtins.h" 10 #include "src/common/globals.h" 11 #include "src/execution/isolate.h" 12 #include "src/heap/code-range.h" 13 14 namespace v8 { 15 namespace internal { 16 17 class Code; 18 class Isolate; 19 20 // Wraps an off-heap instruction stream. 21 // TODO(jgruber,v8:6666): Remove this class. 22 class OffHeapInstructionStream final : public AllStatic { 23 public: 24 // Returns true, iff the given pc points into an off-heap instruction stream. 25 static bool PcIsOffHeap(Isolate* isolate, Address pc); 26 27 // If the address belongs to the embedded code blob, predictably converts it 28 // to uint32 by calculating offset from the embedded code blob start and 29 // returns true, and false otherwise. 30 static bool TryGetAddressForHashing(Isolate* isolate, Address address, 31 uint32_t* hashable_address); 32 33 // Returns the corresponding builtin ID if lookup succeeds, and kNoBuiltinId 34 // otherwise. 35 static Builtin TryLookupCode(Isolate* isolate, Address address); 36 37 // During snapshot creation, we first create an executable off-heap area 38 // containing all off-heap code. The area is guaranteed to be contiguous. 39 // Note that this only applies when building the snapshot, e.g. for 40 // mksnapshot. Otherwise, off-heap code is embedded directly into the binary. 41 static void CreateOffHeapOffHeapInstructionStream(Isolate* isolate, 42 uint8_t** code, 43 uint32_t* code_size, 44 uint8_t** data, 45 uint32_t* data_size); 46 static void FreeOffHeapOffHeapInstructionStream(uint8_t* code, 47 uint32_t code_size, 48 uint8_t* data, 49 uint32_t data_size); 50 }; 51 52 class EmbeddedData final { 53 public: 54 static EmbeddedData FromIsolate(Isolate* isolate); 55 FromBlob()56 static EmbeddedData FromBlob() { 57 return EmbeddedData(Isolate::CurrentEmbeddedBlobCode(), 58 Isolate::CurrentEmbeddedBlobCodeSize(), 59 Isolate::CurrentEmbeddedBlobData(), 60 Isolate::CurrentEmbeddedBlobDataSize()); 61 } 62 FromBlob(Isolate * isolate)63 static EmbeddedData FromBlob(Isolate* isolate) { 64 return EmbeddedData( 65 isolate->embedded_blob_code(), isolate->embedded_blob_code_size(), 66 isolate->embedded_blob_data(), isolate->embedded_blob_data_size()); 67 } 68 FromBlob(CodeRange * code_range)69 static EmbeddedData FromBlob(CodeRange* code_range) { 70 return EmbeddedData(code_range->embedded_blob_code_copy(), 71 Isolate::CurrentEmbeddedBlobCodeSize(), 72 Isolate::CurrentEmbeddedBlobData(), 73 Isolate::CurrentEmbeddedBlobDataSize()); 74 } 75 code()76 const uint8_t* code() const { return code_; } code_size()77 uint32_t code_size() const { return code_size_; } data()78 const uint8_t* data() const { return data_; } data_size()79 uint32_t data_size() const { return data_size_; } 80 IsInCodeRange(Address pc)81 bool IsInCodeRange(Address pc) const { 82 Address start = reinterpret_cast<Address>(code_); 83 return (start <= pc) && (pc < start + code_size_); 84 } 85 86 // When short builtin calls optimization is enabled for the Isolate, there 87 // will be two builtins instruction streams executed: the embedded one and 88 // the one un-embedded into the per-Isolate code range. In most of the cases, 89 // the per-Isolate instructions will be used but in some cases (like builtin 90 // calls from Wasm) the embedded instruction stream could be used. 91 // If the requested PC belongs to the embedded code blob - it'll be returned, 92 // and the per-Isolate blob otherwise. 93 // See http://crbug.com/v8/11527 for details. GetEmbeddedDataForPC(Isolate * isolate,Address maybe_builtin_pc)94 inline static EmbeddedData GetEmbeddedDataForPC(Isolate* isolate, 95 Address maybe_builtin_pc) { 96 EmbeddedData d = EmbeddedData::FromBlob(isolate); 97 if (isolate->is_short_builtin_calls_enabled() && 98 !d.IsInCodeRange(maybe_builtin_pc)) { 99 EmbeddedData global_d = EmbeddedData::FromBlob(); 100 // If the pc does not belong to the embedded code blob we should be using 101 // the un-embedded one. 102 if (global_d.IsInCodeRange(maybe_builtin_pc)) return global_d; 103 } 104 #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE 105 if (V8_SHORT_BUILTIN_CALLS_BOOL && !d.IsInCodeRange(maybe_builtin_pc)) { 106 // When shared pointer compression cage is enabled and it has the embedded 107 // code blob copy then it could have been used regardless of whether the 108 // isolate uses it or knows about it or not (see 109 // Code::OffHeapInstructionStart()). 110 // So, this blob has to be checked too. 111 CodeRange* code_range = CodeRange::GetProcessWideCodeRange().get(); 112 if (code_range && code_range->embedded_blob_code_copy() != nullptr) { 113 EmbeddedData remapped_d = EmbeddedData::FromBlob(code_range); 114 // If the pc does not belong to the embedded code blob we should be 115 // using the un-embedded one. 116 if (remapped_d.IsInCodeRange(maybe_builtin_pc)) return remapped_d; 117 } 118 } 119 #endif 120 return d; 121 } 122 Dispose()123 void Dispose() { 124 delete[] code_; 125 code_ = nullptr; 126 delete[] data_; 127 data_ = nullptr; 128 } 129 130 // TODO(ishell): rename XyzOfBuiltin() to XyzOf(). 131 inline Address InstructionStartOfBuiltin(Builtin builtin) const; 132 inline uint32_t InstructionSizeOfBuiltin(Builtin builtin) const; 133 134 inline Address InstructionStartOfBytecodeHandlers() const; 135 inline Address InstructionEndOfBytecodeHandlers() const; 136 137 inline Address MetadataStartOfBuiltin(Builtin builtin) const; 138 inline uint32_t MetadataSizeOfBuiltin(Builtin builtin) const; 139 140 inline Address SafepointTableStartOf(Builtin builtin) const; 141 inline uint32_t SafepointTableSizeOf(Builtin builtin) const; 142 143 inline Address HandlerTableStartOf(Builtin builtin) const; 144 inline uint32_t HandlerTableSizeOf(Builtin builtin) const; 145 146 inline Address ConstantPoolStartOf(Builtin builtin) const; 147 inline uint32_t ConstantPoolSizeOf(Builtin builtin) const; 148 149 inline Address CodeCommentsStartOf(Builtin builtin) const; 150 inline uint32_t CodeCommentsSizeOf(Builtin builtin) const; 151 152 inline Address UnwindingInfoStartOf(Builtin builtin) const; 153 inline uint32_t UnwindingInfoSizeOf(Builtin builtin) const; 154 AddressForHashing(Address addr)155 uint32_t AddressForHashing(Address addr) { 156 DCHECK(IsInCodeRange(addr)); 157 Address start = reinterpret_cast<Address>(code_); 158 return static_cast<uint32_t>(addr - start); 159 } 160 161 // Padded with kCodeAlignment. 162 // TODO(v8:11045): Consider removing code alignment. 163 inline uint32_t PaddedInstructionSizeOfBuiltin(Builtin builtin) const; 164 165 size_t CreateEmbeddedBlobDataHash() const; 166 size_t CreateEmbeddedBlobCodeHash() const; EmbeddedBlobDataHash()167 size_t EmbeddedBlobDataHash() const { 168 return *reinterpret_cast<const size_t*>(data_ + 169 EmbeddedBlobDataHashOffset()); 170 } EmbeddedBlobCodeHash()171 size_t EmbeddedBlobCodeHash() const { 172 return *reinterpret_cast<const size_t*>(data_ + 173 EmbeddedBlobCodeHashOffset()); 174 } 175 IsolateHash()176 size_t IsolateHash() const { 177 return *reinterpret_cast<const size_t*>(data_ + IsolateHashOffset()); 178 } 179 180 // Blob layout information for a single instruction stream. Corresponds 181 // roughly to Code object layout (see the instruction and metadata area). 182 struct LayoutDescription { 183 // The offset and (unpadded) length of this builtin's instruction area 184 // from the start of the embedded code section. 185 uint32_t instruction_offset; 186 uint32_t instruction_length; 187 // The offset and (unpadded) length of this builtin's metadata area 188 // from the start of the embedded data section. 189 uint32_t metadata_offset; 190 uint32_t metadata_length; 191 192 // The offsets describing inline metadata tables, relative to the start 193 // of the embedded data section. 194 uint32_t handler_table_offset; 195 #if V8_EMBEDDED_CONSTANT_POOL 196 uint32_t constant_pool_offset; 197 #endif 198 uint32_t code_comments_offset_offset; 199 uint32_t unwinding_info_offset_offset; 200 }; 201 STATIC_ASSERT(offsetof(LayoutDescription, instruction_offset) == 202 0 * kUInt32Size); 203 STATIC_ASSERT(offsetof(LayoutDescription, instruction_length) == 204 1 * kUInt32Size); 205 STATIC_ASSERT(offsetof(LayoutDescription, metadata_offset) == 206 2 * kUInt32Size); 207 STATIC_ASSERT(offsetof(LayoutDescription, metadata_length) == 208 3 * kUInt32Size); 209 STATIC_ASSERT(offsetof(LayoutDescription, handler_table_offset) == 210 4 * kUInt32Size); 211 #if V8_EMBEDDED_CONSTANT_POOL 212 STATIC_ASSERT(offsetof(LayoutDescription, constant_pool_offset) == 213 5 * kUInt32Size); 214 STATIC_ASSERT(offsetof(LayoutDescription, code_comments_offset_offset) == 215 6 * kUInt32Size); 216 STATIC_ASSERT(offsetof(LayoutDescription, unwinding_info_offset_offset) == 217 7 * kUInt32Size); 218 STATIC_ASSERT(sizeof(LayoutDescription) == 8 * kUInt32Size); 219 #else 220 STATIC_ASSERT(offsetof(LayoutDescription, code_comments_offset_offset) == 221 5 * kUInt32Size); 222 STATIC_ASSERT(offsetof(LayoutDescription, unwinding_info_offset_offset) == 223 6 * kUInt32Size); 224 STATIC_ASSERT(sizeof(LayoutDescription) == 7 * kUInt32Size); 225 #endif 226 227 // The layout of the blob is as follows: 228 // 229 // data: 230 // [0] hash of the data section 231 // [1] hash of the code section 232 // [2] hash of embedded-blob-relevant heap objects 233 // [3] layout description of instruction stream 0 234 // ... layout descriptions 235 // [x] metadata section of builtin 0 236 // ... metadata sections 237 // 238 // code: 239 // [0] instruction section of builtin 0 240 // ... instruction sections 241 242 static constexpr uint32_t kTableSize = Builtins::kBuiltinCount; EmbeddedBlobDataHashOffset()243 static constexpr uint32_t EmbeddedBlobDataHashOffset() { return 0; } EmbeddedBlobDataHashSize()244 static constexpr uint32_t EmbeddedBlobDataHashSize() { return kSizetSize; } EmbeddedBlobCodeHashOffset()245 static constexpr uint32_t EmbeddedBlobCodeHashOffset() { 246 return EmbeddedBlobDataHashOffset() + EmbeddedBlobDataHashSize(); 247 } EmbeddedBlobCodeHashSize()248 static constexpr uint32_t EmbeddedBlobCodeHashSize() { return kSizetSize; } IsolateHashOffset()249 static constexpr uint32_t IsolateHashOffset() { 250 return EmbeddedBlobCodeHashOffset() + EmbeddedBlobCodeHashSize(); 251 } IsolateHashSize()252 static constexpr uint32_t IsolateHashSize() { return kSizetSize; } LayoutDescriptionTableOffset()253 static constexpr uint32_t LayoutDescriptionTableOffset() { 254 return IsolateHashOffset() + IsolateHashSize(); 255 } LayoutDescriptionTableSize()256 static constexpr uint32_t LayoutDescriptionTableSize() { 257 return sizeof(struct LayoutDescription) * kTableSize; 258 } FixedDataSize()259 static constexpr uint32_t FixedDataSize() { 260 return LayoutDescriptionTableOffset() + LayoutDescriptionTableSize(); 261 } 262 // The variable-size data section starts here. RawMetadataOffset()263 static constexpr uint32_t RawMetadataOffset() { return FixedDataSize(); } 264 265 // Code is in its own dedicated section. RawCodeOffset()266 static constexpr uint32_t RawCodeOffset() { return 0; } 267 268 private: EmbeddedData(const uint8_t * code,uint32_t code_size,const uint8_t * data,uint32_t data_size)269 EmbeddedData(const uint8_t* code, uint32_t code_size, const uint8_t* data, 270 uint32_t data_size) 271 : code_(code), code_size_(code_size), data_(data), data_size_(data_size) { 272 DCHECK_NOT_NULL(code); 273 DCHECK_LT(0, code_size); 274 DCHECK_NOT_NULL(data); 275 DCHECK_LT(0, data_size); 276 } 277 RawCode()278 const uint8_t* RawCode() const { return code_ + RawCodeOffset(); } 279 LayoutDescription(Builtin builtin)280 const LayoutDescription& LayoutDescription(Builtin builtin) const { 281 const struct LayoutDescription* descs = 282 reinterpret_cast<const struct LayoutDescription*>( 283 data_ + LayoutDescriptionTableOffset()); 284 return descs[static_cast<int>(builtin)]; 285 } RawMetadata()286 const uint8_t* RawMetadata() const { return data_ + RawMetadataOffset(); } 287 PadAndAlignCode(int size)288 static constexpr int PadAndAlignCode(int size) { 289 // Ensure we have at least one byte trailing the actual builtin 290 // instructions which we can later fill with int3. 291 return RoundUp<kCodeAlignment>(size + 1); 292 } PadAndAlignData(int size)293 static constexpr int PadAndAlignData(int size) { 294 // Ensure we have at least one byte trailing the actual builtin 295 // instructions which we can later fill with int3. 296 return RoundUp<Code::kMetadataAlignment>(size); 297 } 298 299 void PrintStatistics() const; 300 301 // The code section contains instruction streams. It is guaranteed to have 302 // execute permissions, and may have read permissions. 303 const uint8_t* code_; 304 uint32_t code_size_; 305 306 // The data section contains both descriptions of the code section (hashes, 307 // offsets, sizes) and metadata describing Code objects (see 308 // Code::MetadataStart()). It is guaranteed to have read permissions. 309 const uint8_t* data_; 310 uint32_t data_size_; 311 }; 312 313 } // namespace internal 314 } // namespace v8 315 316 #endif // V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_ 317