V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
reloc-info.h
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_RELOC_INFO_H_
6 #define V8_RELOC_INFO_H_
7 
8 #include "src/globals.h"
9 #include "src/objects.h"
10 #include "src/objects/code.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 class CodeReference;
16 class EmbeddedData;
17 
18 // Specifies whether to perform icache flush operations on RelocInfo updates.
19 // If FLUSH_ICACHE_IF_NEEDED, the icache will always be flushed if an
20 // instruction was modified. If SKIP_ICACHE_FLUSH the flush will always be
21 // skipped (only use this if you will flush the icache manually before it is
22 // executed).
23 enum ICacheFlushMode { FLUSH_ICACHE_IF_NEEDED, SKIP_ICACHE_FLUSH };
24 
25 // -----------------------------------------------------------------------------
26 // Relocation information
27 
28 // Relocation information consists of the address (pc) of the datum
29 // to which the relocation information applies, the relocation mode
30 // (rmode), and an optional data field. The relocation mode may be
31 // "descriptive" and not indicate a need for relocation, but simply
32 // describe a property of the datum. Such rmodes are useful for GC
33 // and nice disassembly output.
34 
35 class RelocInfo {
36  public:
37  // This string is used to add padding comments to the reloc info in cases
38  // where we are not sure to have enough space for patching in during
39  // lazy deoptimization. This is the case if we have indirect calls for which
40  // we do not normally record relocation info.
41  static const char* const kFillerCommentString;
42 
43  // The minimum size of a comment is equal to two bytes for the extra tagged
44  // pc and kPointerSize for the actual pointer to the comment.
45  static const int kMinRelocCommentSize = 2 + kPointerSize;
46 
47  // The maximum size for a call instruction including pc-jump.
48  static const int kMaxCallSize = 6;
49 
50  // The maximum pc delta that will use the short encoding.
51  static const int kMaxSmallPCDelta;
52 
53  enum Mode : int8_t {
54  // Please note the order is important (see IsRealRelocMode, IsGCRelocMode,
55  // and IsShareableRelocMode predicates below).
56 
57  CODE_TARGET,
58  RELATIVE_CODE_TARGET, // LAST_CODE_TARGET_MODE
59  EMBEDDED_OBJECT, // LAST_GCED_ENUM
60 
61  WASM_CALL, // FIRST_SHAREABLE_RELOC_MODE
62  WASM_STUB_CALL,
63 
64  RUNTIME_ENTRY,
65  COMMENT,
66 
67  EXTERNAL_REFERENCE, // The address of an external C++ function.
68  INTERNAL_REFERENCE, // An address inside the same function.
69 
70  // Encoded internal reference, used only on MIPS, MIPS64 and PPC.
71  INTERNAL_REFERENCE_ENCODED,
72 
73  // An off-heap instruction stream target. See http://goo.gl/Z2HUiM.
74  OFF_HEAP_TARGET,
75 
76  // Marks constant and veneer pools. Only used on ARM and ARM64.
77  // They use a custom noncompact encoding.
78  CONST_POOL,
79  VENEER_POOL,
80 
81  DEOPT_SCRIPT_OFFSET,
82  DEOPT_INLINING_ID, // Deoptimization source position.
83  DEOPT_REASON, // Deoptimization reason index.
84  DEOPT_ID, // Deoptimization inlining id.
85 
86  // This is not an actual reloc mode, but used to encode a long pc jump that
87  // cannot be encoded as part of another record.
88  PC_JUMP,
89 
90  // Pseudo-types
91  NUMBER_OF_MODES,
92  NONE, // never recorded value
93 
94  LAST_CODE_TARGET_MODE = RELATIVE_CODE_TARGET,
95  FIRST_REAL_RELOC_MODE = CODE_TARGET,
96  LAST_REAL_RELOC_MODE = VENEER_POOL,
97  LAST_GCED_ENUM = EMBEDDED_OBJECT,
98  FIRST_SHAREABLE_RELOC_MODE = WASM_CALL,
99  };
100 
101  STATIC_ASSERT(NUMBER_OF_MODES <= kBitsPerInt);
102 
103  RelocInfo() = default;
104 
105  RelocInfo(Address pc, Mode rmode, intptr_t data, Code host,
106  Address constant_pool = kNullAddress)
107  : pc_(pc),
108  rmode_(rmode),
109  data_(data),
110  host_(host),
111  constant_pool_(constant_pool) {}
112 
113  static constexpr bool IsRealRelocMode(Mode mode) {
114  return mode >= FIRST_REAL_RELOC_MODE && mode <= LAST_REAL_RELOC_MODE;
115  }
116  // Is the relocation mode affected by GC?
117  static constexpr bool IsGCRelocMode(Mode mode) {
118  return mode <= LAST_GCED_ENUM;
119  }
120  static constexpr bool IsShareableRelocMode(Mode mode) {
121  static_assert(RelocInfo::NONE >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE,
122  "Users of this function rely on NONE being a sharable "
123  "relocation mode.");
124  return mode >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE;
125  }
126  static constexpr bool IsCodeTarget(Mode mode) { return mode == CODE_TARGET; }
127  static constexpr bool IsCodeTargetMode(Mode mode) {
128  return mode <= LAST_CODE_TARGET_MODE;
129  }
130  static constexpr bool IsRelativeCodeTarget(Mode mode) {
131  return mode == RELATIVE_CODE_TARGET;
132  }
133  static constexpr bool IsEmbeddedObject(Mode mode) {
134  return mode == EMBEDDED_OBJECT;
135  }
136  static constexpr bool IsRuntimeEntry(Mode mode) {
137  return mode == RUNTIME_ENTRY;
138  }
139  static constexpr bool IsWasmCall(Mode mode) { return mode == WASM_CALL; }
140  static constexpr bool IsWasmReference(Mode mode) { return mode == WASM_CALL; }
141  static constexpr bool IsWasmStubCall(Mode mode) {
142  return mode == WASM_STUB_CALL;
143  }
144  static constexpr bool IsComment(Mode mode) { return mode == COMMENT; }
145  static constexpr bool IsConstPool(Mode mode) { return mode == CONST_POOL; }
146  static constexpr bool IsVeneerPool(Mode mode) { return mode == VENEER_POOL; }
147  static constexpr bool IsDeoptPosition(Mode mode) {
148  return mode == DEOPT_SCRIPT_OFFSET || mode == DEOPT_INLINING_ID;
149  }
150  static constexpr bool IsDeoptReason(Mode mode) {
151  return mode == DEOPT_REASON;
152  }
153  static constexpr bool IsDeoptId(Mode mode) { return mode == DEOPT_ID; }
154  static constexpr bool IsExternalReference(Mode mode) {
155  return mode == EXTERNAL_REFERENCE;
156  }
157  static constexpr bool IsInternalReference(Mode mode) {
158  return mode == INTERNAL_REFERENCE;
159  }
160  static constexpr bool IsInternalReferenceEncoded(Mode mode) {
161  return mode == INTERNAL_REFERENCE_ENCODED;
162  }
163  static constexpr bool IsOffHeapTarget(Mode mode) {
164  return mode == OFF_HEAP_TARGET;
165  }
166  static constexpr bool IsNone(Mode mode) { return mode == NONE; }
167 
168  static bool IsOnlyForSerializer(Mode mode) {
169 #ifdef V8_TARGET_ARCH_IA32
170  // On ia32, inlined off-heap trampolines must be relocated.
171  DCHECK_NE((kApplyMask & ModeMask(OFF_HEAP_TARGET)), 0);
172  DCHECK_EQ((kApplyMask & ModeMask(EXTERNAL_REFERENCE)), 0);
173  return mode == EXTERNAL_REFERENCE;
174 #else
175  DCHECK_EQ((kApplyMask & ModeMask(OFF_HEAP_TARGET)), 0);
176  DCHECK_EQ((kApplyMask & ModeMask(EXTERNAL_REFERENCE)), 0);
177  return mode == EXTERNAL_REFERENCE || mode == OFF_HEAP_TARGET;
178 #endif
179  }
180 
181  static constexpr int ModeMask(Mode mode) { return 1 << mode; }
182 
183  // Accessors
184  Address pc() const { return pc_; }
185  Mode rmode() const { return rmode_; }
186  intptr_t data() const { return data_; }
187  Code host() const { return host_; }
188  Address constant_pool() const { return constant_pool_; }
189 
190  // Apply a relocation by delta bytes. When the code object is moved, PC
191  // relative addresses have to be updated as well as absolute addresses
192  // inside the code (internal references).
193  // Do not forget to flush the icache afterwards!
194  V8_INLINE void apply(intptr_t delta);
195 
196  // Is the pointer this relocation info refers to coded like a plain pointer
197  // or is it strange in some way (e.g. relative or patched into a series of
198  // instructions).
199  bool IsCodedSpecially();
200 
201  // The static pendant to IsCodedSpecially, just for off-heap targets. Used
202  // during deserialization, when we don't actually have a RelocInfo handy.
203  static bool OffHeapTargetIsCodedSpecially();
204 
205  // If true, the pointer this relocation info refers to is an entry in the
206  // constant pool, otherwise the pointer is embedded in the instruction stream.
207  bool IsInConstantPool();
208 
209  // Returns the deoptimization id for the entry associated with the reloc info
210  // where {kind} is the deoptimization kind.
211  // This is only used for printing RUNTIME_ENTRY relocation info.
212  int GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind);
213 
214  Address wasm_call_address() const;
215  Address wasm_stub_call_address() const;
216 
217  uint32_t wasm_call_tag() const;
218 
219  void set_wasm_call_address(
220  Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
221  void set_wasm_stub_call_address(
222  Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
223 
224  void set_target_address(
225  Address target,
226  WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
227  ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
228 
229  // this relocation applies to;
230  // can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
231  V8_INLINE Address target_address();
232  V8_INLINE HeapObject* target_object();
233  V8_INLINE Handle<HeapObject> target_object_handle(Assembler* origin);
234  V8_INLINE void set_target_object(
235  Heap* heap, HeapObject* target,
236  WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
237  ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
238  V8_INLINE Address target_runtime_entry(Assembler* origin);
239  V8_INLINE void set_target_runtime_entry(
240  Address target,
241  WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
242  ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
243  V8_INLINE Address target_off_heap_target();
244  V8_INLINE Cell* target_cell();
245  V8_INLINE Handle<Cell> target_cell_handle();
246  V8_INLINE void set_target_cell(
247  Cell* cell, WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
248  ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
249  V8_INLINE void set_target_external_reference(
250  Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
251 
252  // Returns the address of the constant pool entry where the target address
253  // is held. This should only be called if IsInConstantPool returns true.
254  V8_INLINE Address constant_pool_entry_address();
255 
256  // Read the address of the word containing the target_address in an
257  // instruction stream. What this means exactly is architecture-independent.
258  // The only architecture-independent user of this function is the serializer.
259  // The serializer uses it to find out how many raw bytes of instruction to
260  // output before the next target. Architecture-independent code shouldn't
261  // dereference the pointer it gets back from this.
262  V8_INLINE Address target_address_address();
263 
264  // This indicates how much space a target takes up when deserializing a code
265  // stream. For most architectures this is just the size of a pointer. For
266  // an instruction like movw/movt where the target bits are mixed into the
267  // instruction bits the size of the target will be zero, indicating that the
268  // serializer should not step forwards in memory after a target is resolved
269  // and written. In this case the target_address_address function above
270  // should return the end of the instructions to be patched, allowing the
271  // deserializer to deserialize the instructions as raw bytes and put them in
272  // place, ready to be patched with the target.
273  V8_INLINE int target_address_size();
274 
275  // Read the reference in the instruction this relocation
276  // applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
277  V8_INLINE Address target_external_reference();
278 
279  // Read the reference in the instruction this relocation
280  // applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
281  V8_INLINE Address target_internal_reference();
282 
283  // Return the reference address this relocation applies to;
284  // can only be called if rmode_ is INTERNAL_REFERENCE.
285  V8_INLINE Address target_internal_reference_address();
286 
287  // Wipe out a relocation to a fixed value, used for making snapshots
288  // reproducible.
289  V8_INLINE void WipeOut();
290 
291  template <typename ObjectVisitor>
292  inline void Visit(ObjectVisitor* v);
293 
294  // Check whether the given code contains relocation information that
295  // either is position-relative or movable by the garbage collector.
296  static bool RequiresRelocationAfterCodegen(const CodeDesc& desc);
297  static bool RequiresRelocation(Code code);
298 
299 #ifdef ENABLE_DISASSEMBLER
300  // Printing
301  static const char* RelocModeName(Mode rmode);
302  void Print(Isolate* isolate, std::ostream& os); // NOLINT
303 #endif // ENABLE_DISASSEMBLER
304 #ifdef VERIFY_HEAP
305  void Verify(Isolate* isolate);
306 #endif
307 
308  static const int kApplyMask; // Modes affected by apply. Depends on arch.
309 
310  // In addition to modes covered by the apply mask (which is applied at GC
311  // time, among others), this covers all modes that are relocated by
312  // Code::CopyFromNoFlush after code generation.
313  static int PostCodegenRelocationMask() {
314  return ModeMask(RelocInfo::CODE_TARGET) |
315  ModeMask(RelocInfo::EMBEDDED_OBJECT) |
316  ModeMask(RelocInfo::RUNTIME_ENTRY) |
317  ModeMask(RelocInfo::RELATIVE_CODE_TARGET) | kApplyMask;
318  }
319 
320  private:
321  // On ARM/ARM64, note that pc_ is the address of the instruction referencing
322  // the constant pool and not the address of the constant pool entry.
323  Address pc_;
324  Mode rmode_;
325  intptr_t data_ = 0;
326  Code host_;
327  Address constant_pool_ = kNullAddress;
328  friend class RelocIterator;
329 };
330 
331 // RelocInfoWriter serializes a stream of relocation info. It writes towards
332 // lower addresses.
334  public:
335  RelocInfoWriter() : pos_(nullptr), last_pc_(nullptr) {}
336 
337  byte* pos() const { return pos_; }
338  byte* last_pc() const { return last_pc_; }
339 
340  void Write(const RelocInfo* rinfo);
341 
342  // Update the state of the stream after reloc info buffer
343  // and/or code is moved while the stream is active.
344  void Reposition(byte* pos, byte* pc) {
345  pos_ = pos;
346  last_pc_ = pc;
347  }
348 
349  // Max size (bytes) of a written RelocInfo. Longest encoding is
350  // ExtraTag, VariableLengthPCJump, ExtraTag, pc_delta, data_delta.
351  static constexpr int kMaxSize = 1 + 4 + 1 + 1 + kPointerSize;
352 
353  private:
354  inline uint32_t WriteLongPCJump(uint32_t pc_delta);
355 
356  inline void WriteShortTaggedPC(uint32_t pc_delta, int tag);
357  inline void WriteShortData(intptr_t data_delta);
358 
359  inline void WriteMode(RelocInfo::Mode rmode);
360  inline void WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode);
361  inline void WriteIntData(int data_delta);
362  inline void WriteData(intptr_t data_delta);
363 
364  byte* pos_;
365  byte* last_pc_;
366 
367  DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
368 };
369 
370 // A RelocIterator iterates over relocation information.
371 // Typical use:
372 //
373 // for (RelocIterator it(code); !it.done(); it.next()) {
374 // // do something with it.rinfo() here
375 // }
376 //
377 // A mask can be specified to skip unwanted modes.
378 class RelocIterator : public Malloced {
379  public:
380  // Create a new iterator positioned at
381  // the beginning of the reloc info.
382  // Relocation information with mode k is included in the
383  // iteration iff bit k of mode_mask is set.
384  explicit RelocIterator(Code code, int mode_mask = -1);
385  explicit RelocIterator(Code code, ByteArray relocation_info, int mode_mask);
386  explicit RelocIterator(EmbeddedData* embedded_data, Code code, int mode_mask);
387  explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
388  explicit RelocIterator(const CodeReference code_reference,
389  int mode_mask = -1);
390  explicit RelocIterator(Vector<byte> instructions,
391  Vector<const byte> reloc_info, Address const_pool,
392  int mode_mask = -1);
393  RelocIterator(RelocIterator&&) = default;
394 
395  // Iteration
396  bool done() const { return done_; }
397  void next();
398 
399  // Return pointer valid until next next().
400  RelocInfo* rinfo() {
401  DCHECK(!done());
402  return &rinfo_;
403  }
404 
405  private:
406  RelocIterator(Code host, Address pc, Address constant_pool, const byte* pos,
407  const byte* end, int mode_mask);
408 
409  // Advance* moves the position before/after reading.
410  // *Read* reads from current byte(s) into rinfo_.
411  // *Get* just reads and returns info on current byte.
412  void Advance(int bytes = 1) { pos_ -= bytes; }
413  int AdvanceGetTag();
414  RelocInfo::Mode GetMode();
415 
416  void AdvanceReadLongPCJump();
417 
418  void ReadShortTaggedPC();
419  void ReadShortData();
420 
421  void AdvanceReadPC();
422  void AdvanceReadInt();
423  void AdvanceReadData();
424 
425  // If the given mode is wanted, set it in rinfo_ and return true.
426  // Else return false. Used for efficiently skipping unwanted modes.
427  bool SetMode(RelocInfo::Mode mode) {
428  return (mode_mask_ & (1 << mode)) ? (rinfo_.rmode_ = mode, true) : false;
429  }
430 
431  const byte* pos_;
432  const byte* end_;
433  RelocInfo rinfo_;
434  bool done_ = false;
435  const int mode_mask_;
436 
437  DISALLOW_COPY_AND_ASSIGN(RelocIterator);
438 };
439 
440 } // namespace internal
441 } // namespace v8
442 
443 #endif // V8_RELOC_INFO_H_
Definition: libplatform.h:13