/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/snapshot/embedded/embedded-data.h
319 строк
13 KB
Michaël Zasso
deps: update V8 to 12.8.374.13
16 авг 2024, 17:03
Не верифицирован
16 авг 2024, 17:03
9d7cd9b
Код
Авторство
О чём код?
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_ #define V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_ #include "src/base/macros.h" #include "src/builtins/builtins.h" #include "src/common/globals.h" #include "src/execution/isolate.h" #include "src/heap/code-range.h" #include "src/objects/instruction-stream.h" namespace v8 { namespace internal { class InstructionStream; class Isolate; using ReorderedBuiltinIndex = uint32_t; // Wraps an off-heap instruction stream. // TODO(jgruber,v8:6666): Remove this class. class OffHeapInstructionStream final : public AllStatic { public: // Returns true, iff the given pc points into an off-heap instruction stream. static bool PcIsOffHeap(Isolate* isolate, Address pc); // If the address belongs to the embedded code blob, predictably converts it // to uint32 by calculating offset from the embedded code blob start and // returns true, and false otherwise. static bool TryGetAddressForHashing(Isolate* isolate, Address address, uint32_t* hashable_address); // Returns the corresponding builtin ID if lookup succeeds, and kNoBuiltinId // otherwise. static Builtin TryLookupCode(Isolate* isolate, Address address); // During snapshot creation, we first create an executable off-heap area // containing all off-heap code. The area is guaranteed to be contiguous. // Note that this only applies when building the snapshot, e.g. for // mksnapshot. Otherwise, off-heap code is embedded directly into the binary. static void CreateOffHeapOffHeapInstructionStream(Isolate* isolate, uint8_t** code, uint32_t* code_size, uint8_t** data, uint32_t* data_size); static void FreeOffHeapOffHeapInstructionStream(uint8_t* code, uint32_t code_size, uint8_t* data, uint32_t data_size); }; class EmbeddedData final { public: // Create the embedded blob from the given Isolate's heap state. static EmbeddedData NewFromIsolate(Isolate* isolate); // Returns the global embedded blob (usually physically located in .text and // .rodata). static EmbeddedData FromBlob() { return EmbeddedData(Isolate::CurrentEmbeddedBlobCode(), Isolate::CurrentEmbeddedBlobCodeSize(), Isolate::CurrentEmbeddedBlobData(), Isolate::CurrentEmbeddedBlobDataSize()); } // Returns a potentially remapped embedded blob (see also // MaybeRemapEmbeddedBuiltinsIntoCodeRange). static EmbeddedData FromBlob(Isolate* isolate) { return EmbeddedData( isolate->embedded_blob_code(), isolate->embedded_blob_code_size(), isolate->embedded_blob_data(), isolate->embedded_blob_data_size()); } // Returns a potentially remapped embedded blob (see also // MaybeRemapEmbeddedBuiltinsIntoCodeRange). static EmbeddedData FromBlob(CodeRange* code_range) { return EmbeddedData(code_range->embedded_blob_code_copy(), Isolate::CurrentEmbeddedBlobCodeSize(), Isolate::CurrentEmbeddedBlobData(), Isolate::CurrentEmbeddedBlobDataSize()); } // When short builtin calls optimization is enabled for the Isolate, there // will be two builtins instruction streams executed: the embedded one and // the one un-embedded into the per-Isolate code range. In most of the cases, // the per-Isolate instructions will be used but in some cases (like builtin // calls from Wasm) the embedded instruction stream could be used. If the // requested PC belongs to the embedded code blob - it'll be returned, and // the per-Isolate blob otherwise. // See http://crbug.com/v8/11527 for details. static EmbeddedData FromBlobForPc(Isolate* isolate, Address maybe_builtin_pc) { EmbeddedData d = EmbeddedData::FromBlob(isolate); if (d.IsInCodeRange(maybe_builtin_pc)) return d; if (isolate->is_short_builtin_calls_enabled()) { EmbeddedData global_d = EmbeddedData::FromBlob(); // If the pc does not belong to the embedded code blob we should be using // the un-embedded one. if (global_d.IsInCodeRange(maybe_builtin_pc)) return global_d; } #if defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE) && \ defined(V8_SHORT_BUILTIN_CALLS) // When shared pointer compression cage is enabled and it has the embedded // code blob copy then it could have been used regardless of whether the // isolate uses it or knows about it or not (see // InstructionStream::OffHeapInstructionStart()). // So, this blob has to be checked too. CodeRange* code_range = IsolateGroup::current()->GetCodeRange(); if (code_range && code_range->embedded_blob_code_copy() != nullptr) { EmbeddedData remapped_d = EmbeddedData::FromBlob(code_range); // If the pc does not belong to the embedded code blob we should be // using the un-embedded one. if (remapped_d.IsInCodeRange(maybe_builtin_pc)) return remapped_d; } #endif // defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE) && // defined(V8_SHORT_BUILTIN_CALLS) return d; } const uint8_t* code() const { return code_; } uint32_t code_size() const { return code_size_; } const uint8_t* data() const { return data_; } uint32_t data_size() const { return data_size_; } bool IsInCodeRange(Address pc) const { Address start = reinterpret_cast<Address>(code_); return (start <= pc) && (pc < start + code_size_); } void Dispose() { delete[] code_; code_ = nullptr; delete[] data_; data_ = nullptr; } inline Address InstructionStartOf(Builtin builtin) const; inline Address InstructionEndOf(Builtin builtin) const; inline uint32_t InstructionSizeOf(Builtin builtin) const; inline Address InstructionStartOfBytecodeHandlers() const; inline Address InstructionEndOfBytecodeHandlers() const; inline Address MetadataStartOf(Builtin builtin) const; uint32_t AddressForHashing(Address addr) { DCHECK(IsInCodeRange(addr)); Address start = reinterpret_cast<Address>(code_); return static_cast<uint32_t>(addr - start); } // Padded with kCodeAlignment. inline uint32_t PaddedInstructionSizeOf(Builtin builtin) const; size_t CreateEmbeddedBlobDataHash() const; size_t CreateEmbeddedBlobCodeHash() const; size_t EmbeddedBlobDataHash() const { return *reinterpret_cast<const size_t*>(data_ + EmbeddedBlobDataHashOffset()); } size_t EmbeddedBlobCodeHash() const { return *reinterpret_cast<const size_t*>(data_ + EmbeddedBlobCodeHashOffset()); } size_t IsolateHash() const { return *reinterpret_cast<const size_t*>(data_ + IsolateHashOffset()); } Builtin TryLookupCode(Address address) const; // Blob layout information for a single instruction stream. struct LayoutDescription { // The offset and (unpadded) length of this builtin's instruction area // from the start of the embedded code section. uint32_t instruction_offset; uint32_t instruction_length; // The offset of this builtin's metadata area from the start of the // embedded data section. uint32_t metadata_offset; }; static_assert(offsetof(LayoutDescription, instruction_offset) == 0 * kUInt32Size); static_assert(offsetof(LayoutDescription, instruction_length) == 1 * kUInt32Size); static_assert(offsetof(LayoutDescription, metadata_offset) == 2 * kUInt32Size); // The embedded code section stores builtins in the so-called // 'embedded snapshot order' which is usually different from the order // as defined by the Builtins enum ('builtin id order'), and determined // through an algorithm based on collected execution profiles. The // BuiltinLookupEntry struct maps from the 'embedded snapshot order' to // the 'builtin id order' and additionally keeps a copy of instruction_end for // each builtin since it is convenient for binary search. struct BuiltinLookupEntry { // The end offset (including padding) of builtin, the end_offset field // should be in ascending order in the array in snapshot, because we will // use it in TryLookupCode. It should be equal to // LayoutDescription[builtin_id].instruction_offset + // PadAndAlignCode(length) uint32_t end_offset; // The id of builtin. uint32_t builtin_id; }; static_assert(offsetof(BuiltinLookupEntry, end_offset) == 0 * kUInt32Size); static_assert(offsetof(BuiltinLookupEntry, builtin_id) == 1 * kUInt32Size); Builtin GetBuiltinId(ReorderedBuiltinIndex embedded_index) const; // The layout of the blob is as follows: // // data: // [0] hash of the data section // [1] hash of the code section // [2] hash of embedded-blob-relevant heap objects // [3] layout description of builtin 0 // ... layout descriptions (builtin id order) // [n] builtin lookup table where entries are sorted by offset_end in // ascending order. (embedded snapshot order) // [x] metadata section of builtin 0 // ... metadata sections (builtin id order) // // code: // [0] instruction section of builtin 0 // ... instruction sections (embedded snapshot order) static constexpr uint32_t kTableSize = Builtins::kBuiltinCount; static constexpr uint32_t EmbeddedBlobDataHashOffset() { return 0; } static constexpr uint32_t EmbeddedBlobDataHashSize() { return kSizetSize; } static constexpr uint32_t EmbeddedBlobCodeHashOffset() { return EmbeddedBlobDataHashOffset() + EmbeddedBlobDataHashSize(); } static constexpr uint32_t EmbeddedBlobCodeHashSize() { return kSizetSize; } static constexpr uint32_t IsolateHashOffset() { return EmbeddedBlobCodeHashOffset() + EmbeddedBlobCodeHashSize(); } static constexpr uint32_t IsolateHashSize() { return kSizetSize; } static constexpr uint32_t LayoutDescriptionTableOffset() { return IsolateHashOffset() + IsolateHashSize(); } static constexpr uint32_t LayoutDescriptionTableSize() { return sizeof(struct LayoutDescription) * kTableSize; } static constexpr uint32_t BuiltinLookupEntryTableOffset() { return LayoutDescriptionTableOffset() + LayoutDescriptionTableSize(); } static constexpr uint32_t BuiltinLookupEntryTableSize() { return sizeof(struct BuiltinLookupEntry) * kTableSize; } static constexpr uint32_t FixedDataSize() { return BuiltinLookupEntryTableOffset() + BuiltinLookupEntryTableSize(); } // The variable-size data section starts here. static constexpr uint32_t RawMetadataOffset() { return FixedDataSize(); } // Code is in its own dedicated section. static constexpr uint32_t RawCodeOffset() { return 0; } private: EmbeddedData(const uint8_t* code, uint32_t code_size, const uint8_t* data, uint32_t data_size) : code_(code), code_size_(code_size), data_(data), data_size_(data_size) { DCHECK_NOT_NULL(code); DCHECK_LT(0, code_size); DCHECK_NOT_NULL(data); DCHECK_LT(0, data_size); } const uint8_t* RawCode() const { return code_ + RawCodeOffset(); } const LayoutDescription& LayoutDescription(Builtin builtin) const { const struct LayoutDescription* descs = reinterpret_cast<const struct LayoutDescription*>( data_ + LayoutDescriptionTableOffset()); return descs[static_cast<int>(builtin)]; } const BuiltinLookupEntry* BuiltinLookupEntry( ReorderedBuiltinIndex index) const { const struct BuiltinLookupEntry* entries = reinterpret_cast<const struct BuiltinLookupEntry*>( data_ + BuiltinLookupEntryTableOffset()); return entries + index; } const uint8_t* RawMetadata() const { return data_ + RawMetadataOffset(); } static constexpr int PadAndAlignCode(int size) { // Ensure we have at least one byte trailing the actual builtin // instructions which we can later fill with int3. return RoundUp<kCodeAlignment>(size + 1); } static constexpr int PadAndAlignData(int size) { // Ensure we have at least one byte trailing the actual builtin // instructions which we can later fill with int3. return RoundUp<InstructionStream::kMetadataAlignment>(size); } void PrintStatistics() const; // The code section contains instruction streams. It is guaranteed to have // execute permissions, and may have read permissions. const uint8_t* code_; uint32_t code_size_; // The data section contains both descriptions of the code section (hashes, // offsets, sizes) and metadata describing InstructionStream objects (see // InstructionStream::MetadataStart()). It is guaranteed to have read // permissions. const uint8_t* data_; uint32_t data_size_; }; } // namespace internal } // namespace v8 #endif // V8_SNAPSHOT_EMBEDDED_EMBEDDED_DATA_H_