LCOV - code coverage report
Current view: top level - src - reloc-info.h (source / functions) Hit Total Coverage
Test: app.info Lines: 25 26 96.2 %
Date: 2019-04-17 Functions: 2 2 100.0 %

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

Generated by: LCOV version 1.10