// 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" namespace v8 { namespace internal { class Code; class Isolate; // 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: 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()); } static EmbeddedData FromBlob(CodeRange* code_range) { return EmbeddedData(code_range->embedded_blob_code_copy(), Isolate::CurrentEmbeddedBlobCodeSize(), Isolate::CurrentEmbeddedBlobData(), Isolate::CurrentEmbeddedBlobDataSize()); } 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
(code_); return (start <= pc) && (pc < start + code_size_); } // 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. inline static EmbeddedData GetEmbeddedDataForPC(Isolate* isolate, Address maybe_builtin_pc) { EmbeddedData d = EmbeddedData::FromBlob(isolate); if (isolate->is_short_builtin_calls_enabled() && !d.IsInCodeRange(maybe_builtin_pc)) { 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; } #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE if (V8_SHORT_BUILTIN_CALLS_BOOL && !d.IsInCodeRange(maybe_builtin_pc)) { // 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 // Code::OffHeapInstructionStart()). // So, this blob has to be checked too. CodeRange* code_range = CodeRange::GetProcessWideCodeRange().get(); 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 return d; } void Dispose() { delete[] code_; code_ = nullptr; delete[] data_; data_ = nullptr; } // TODO(ishell): rename XyzOfBuiltin() to XyzOf(). inline Address InstructionStartOfBuiltin(Builtin builtin) const; inline uint32_t InstructionSizeOfBuiltin(Builtin builtin) const; inline Address InstructionStartOfBytecodeHandlers() const; inline Address InstructionEndOfBytecodeHandlers() const; inline Address MetadataStartOfBuiltin(Builtin builtin) const; inline uint32_t MetadataSizeOfBuiltin(Builtin builtin) const; inline Address SafepointTableStartOf(Builtin builtin) const; inline uint32_t SafepointTableSizeOf(Builtin builtin) const; inline Address HandlerTableStartOf(Builtin builtin) const; inline uint32_t HandlerTableSizeOf(Builtin builtin) const; inline Address ConstantPoolStartOf(Builtin builtin) const; inline uint32_t ConstantPoolSizeOf(Builtin builtin) const; inline Address CodeCommentsStartOf(Builtin builtin) const; inline uint32_t CodeCommentsSizeOf(Builtin builtin) const; inline Address UnwindingInfoStartOf(Builtin builtin) const; inline uint32_t UnwindingInfoSizeOf(Builtin builtin) const; uint32_t AddressForHashing(Address addr) { DCHECK(IsInCodeRange(addr)); Address start = reinterpret_cast(code_); return static_cast