• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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