|  | // 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" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  |  | 
|  | class Code; | 
|  | class Isolate; | 
|  |  | 
|  | // Wraps an off-heap instruction stream. | 
|  | // TODO(jgruber,v8:6666): Remove this class. | 
|  | class InstructionStream final : public AllStatic { | 
|  | public: | 
|  | // Returns true, iff the given pc points into an off-heap instruction stream. | 
|  | static bool PcIsOffHeap(Isolate* isolate, Address pc); | 
|  |  | 
|  | // Returns the corresponding Code object if it exists, and nullptr otherwise. | 
|  | static Code 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 CreateOffHeapInstructionStream(Isolate* isolate, uint8_t** code, | 
|  | uint32_t* code_size, | 
|  | uint8_t** data, | 
|  | uint32_t* data_size); | 
|  | static void FreeOffHeapInstructionStream(uint8_t* code, uint32_t code_size, | 
|  | uint8_t* data, uint32_t data_size); | 
|  | }; | 
|  |  | 
|  | class EmbeddedData final { | 
|  | public: | 
|  | static EmbeddedData FromIsolate(Isolate* isolate); | 
|  |  | 
|  | static EmbeddedData FromBlob() { | 
|  | return EmbeddedData(Isolate::CurrentEmbeddedBlobCode(), | 
|  | Isolate::CurrentEmbeddedBlobCodeSize(), | 
|  | Isolate::CurrentEmbeddedBlobData(), | 
|  | Isolate::CurrentEmbeddedBlobDataSize()); | 
|  | } | 
|  |  | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | 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_; } | 
|  |  | 
|  | void Dispose() { | 
|  | delete[] code_; | 
|  | code_ = nullptr; | 
|  | delete[] data_; | 
|  | data_ = nullptr; | 
|  | } | 
|  |  | 
|  | Address InstructionStartOfBuiltin(int i) const; | 
|  | uint32_t InstructionSizeOfBuiltin(int i) const; | 
|  |  | 
|  | Address InstructionStartOfBytecodeHandlers() const; | 
|  | Address InstructionEndOfBytecodeHandlers() const; | 
|  |  | 
|  | Address MetadataStartOfBuiltin(int i) const; | 
|  | uint32_t MetadataSizeOfBuiltin(int i) const; | 
|  |  | 
|  | uint32_t AddressForHashing(Address addr) { | 
|  | Address start = reinterpret_cast<Address>(code_); | 
|  | DCHECK(base::IsInRange(addr, start, start + code_size_)); | 
|  | return static_cast<uint32_t>(addr - start); | 
|  | } | 
|  |  | 
|  | // Padded with kCodeAlignment. | 
|  | // TODO(v8:11045): Consider removing code alignment. | 
|  | uint32_t PaddedInstructionSizeOfBuiltin(int i) const { | 
|  | uint32_t size = InstructionSizeOfBuiltin(i); | 
|  | CHECK_NE(size, 0); | 
|  | return PadAndAlignCode(size); | 
|  | } | 
|  |  | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | // Blob layout information for a single instruction stream. Corresponds | 
|  | // roughly to Code object layout (see the instruction and metadata area). | 
|  | 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 and (unpadded) length of this builtin's metadata area | 
|  | // from the start of the embedded code section. | 
|  | uint32_t metadata_offset; | 
|  | uint32_t metadata_length; | 
|  | }; | 
|  | STATIC_ASSERT(offsetof(LayoutDescription, instruction_offset) == | 
|  | 0 * kUInt32Size); | 
|  | STATIC_ASSERT(offsetof(LayoutDescription, instruction_length) == | 
|  | 1 * kUInt32Size); | 
|  | STATIC_ASSERT(offsetof(LayoutDescription, metadata_offset) == | 
|  | 2 * kUInt32Size); | 
|  | STATIC_ASSERT(offsetof(LayoutDescription, metadata_length) == | 
|  | 3 * kUInt32Size); | 
|  | STATIC_ASSERT(sizeof(LayoutDescription) == 4 * kUInt32Size); | 
|  |  | 
|  | // 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 instruction stream 0 | 
|  | // ... layout descriptions | 
|  | // [x] metadata section of builtin 0 | 
|  | // ... metadata sections | 
|  | // | 
|  | // code: | 
|  | // [0] instruction section of builtin 0 | 
|  | // ... instruction sections | 
|  |  | 
|  | static constexpr uint32_t kTableSize = Builtins::builtin_count; | 
|  | 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 FixedDataSize() { | 
|  | return LayoutDescriptionTableOffset() + LayoutDescriptionTableSize(); | 
|  | } | 
|  | // 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() const { | 
|  | return reinterpret_cast<const struct LayoutDescription*>( | 
|  | data_ + LayoutDescriptionTableOffset()); | 
|  | } | 
|  | 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<Code::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 Code objects (see | 
|  | // Code::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_ |