LCOV - code coverage report
Current view: top level - src - reloc-info.h (source / functions) Hit Total Coverage
Test: app.info Lines: 23 23 100.0 %
Date: 2019-01-20 Functions: 9 10 90.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/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             : 
      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   209420433 :   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    12144961 :         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      257283 :   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      379404 :   static constexpr bool IsEmbeddedObject(Mode mode) {
     133      379404 :     return mode == EMBEDDED_OBJECT;
     134             :   }
     135      256601 :   static constexpr bool IsRuntimeEntry(Mode mode) {
     136      256601 :     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   179084389 :     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      379379 :   static constexpr bool IsExternalReference(Mode mode) {
     153      379379 :     return mode == EXTERNAL_REFERENCE;
     154             :   }
     155      609223 :   static constexpr bool IsInternalReference(Mode mode) {
     156      609223 :     return mode == INTERNAL_REFERENCE;
     157             :   }
     158             :   static constexpr bool IsInternalReferenceEncoded(Mode mode) {
     159             :     return mode == INTERNAL_REFERENCE_ENCODED;
     160             :   }
     161      379261 :   static constexpr bool IsOffHeapTarget(Mode mode) {
     162      379261 :     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    17595524 :     return mode == EXTERNAL_REFERENCE || mode == OFF_HEAP_TARGET;
     176             : #endif
     177             :   }
     178             : 
     179        1178 :   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    12349631 :   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             :   inline void Visit(ObjectVisitor* v);
     282             : 
     283             :   // Check whether the given code contains relocation information that
     284             :   // either is position-relative or movable by the garbage collector.
     285             :   static bool RequiresRelocationAfterCodegen(const CodeDesc& desc);
     286             :   static bool RequiresRelocation(Code code);
     287             : 
     288             : #ifdef ENABLE_DISASSEMBLER
     289             :   // Printing
     290             :   static const char* RelocModeName(Mode rmode);
     291             :   void Print(Isolate* isolate, std::ostream& os);  // NOLINT
     292             : #endif                                             // ENABLE_DISASSEMBLER
     293             : #ifdef VERIFY_HEAP
     294             :   void Verify(Isolate* isolate);
     295             : #endif
     296             : 
     297             :   static const int kApplyMask;  // Modes affected by apply.  Depends on arch.
     298             : 
     299             :   // In addition to modes covered by the apply mask (which is applied at GC
     300             :   // time, among others), this covers all modes that are relocated by
     301             :   // Code::CopyFromNoFlush after code generation.
     302             :   static int PostCodegenRelocationMask() {
     303             :     return ModeMask(RelocInfo::CODE_TARGET) |
     304             :            ModeMask(RelocInfo::EMBEDDED_OBJECT) |
     305             :            ModeMask(RelocInfo::RUNTIME_ENTRY) |
     306     2200274 :            ModeMask(RelocInfo::RELATIVE_CODE_TARGET) | kApplyMask;
     307             :   }
     308             : 
     309             :  private:
     310             :   // On ARM/ARM64, note that pc_ is the address of the instruction referencing
     311             :   // the constant pool and not the address of the constant pool entry.
     312             :   Address pc_;
     313             :   Mode rmode_;
     314             :   intptr_t data_ = 0;
     315             :   Code host_;
     316             :   Address constant_pool_ = kNullAddress;
     317             :   friend class RelocIterator;
     318             : };
     319             : 
     320             : // RelocInfoWriter serializes a stream of relocation info. It writes towards
     321             : // lower addresses.
     322             : class RelocInfoWriter {
     323             :  public:
     324     6477615 :   RelocInfoWriter() : pos_(nullptr), last_pc_(nullptr) {}
     325             : 
     326             :   byte* pos() const { return pos_; }
     327             :   byte* last_pc() const { return last_pc_; }
     328             : 
     329             :   void Write(const RelocInfo* rinfo);
     330             : 
     331             :   // Update the state of the stream after reloc info buffer
     332             :   // and/or code is moved while the stream is active.
     333             :   void Reposition(byte* pos, byte* pc) {
     334     6518684 :     pos_ = pos;
     335     6518684 :     last_pc_ = pc;
     336             :   }
     337             : 
     338             :   // Max size (bytes) of a written RelocInfo. Longest encoding is
     339             :   // ExtraTag, VariableLengthPCJump, ExtraTag, pc_delta, data_delta.
     340             :   static constexpr int kMaxSize = 1 + 4 + 1 + 1 + kPointerSize;
     341             : 
     342             :  private:
     343             :   inline uint32_t WriteLongPCJump(uint32_t pc_delta);
     344             : 
     345             :   inline void WriteShortTaggedPC(uint32_t pc_delta, int tag);
     346             :   inline void WriteShortData(intptr_t data_delta);
     347             : 
     348             :   inline void WriteMode(RelocInfo::Mode rmode);
     349             :   inline void WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode);
     350             :   inline void WriteIntData(int data_delta);
     351             :   inline void WriteData(intptr_t data_delta);
     352             : 
     353             :   byte* pos_;
     354             :   byte* last_pc_;
     355             : 
     356             :   DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
     357             : };
     358             : 
     359             : // A RelocIterator iterates over relocation information.
     360             : // Typical use:
     361             : //
     362             : //   for (RelocIterator it(code); !it.done(); it.next()) {
     363             : //     // do something with it.rinfo() here
     364             : //   }
     365             : //
     366             : // A mask can be specified to skip unwanted modes.
     367             : class RelocIterator : public Malloced {
     368             :  public:
     369             :   // Create a new iterator positioned at
     370             :   // the beginning of the reloc info.
     371             :   // Relocation information with mode k is included in the
     372             :   // iteration iff bit k of mode_mask is set.
     373             :   explicit RelocIterator(Code code, int mode_mask = -1);
     374             :   explicit RelocIterator(Code code, ByteArray relocation_info, int mode_mask);
     375             :   explicit RelocIterator(EmbeddedData* embedded_data, Code code, int mode_mask);
     376             :   explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
     377             :   explicit RelocIterator(const CodeReference code_reference,
     378             :                          int mode_mask = -1);
     379             :   explicit RelocIterator(Vector<byte> instructions,
     380             :                          Vector<const byte> reloc_info, Address const_pool,
     381             :                          int mode_mask = -1);
     382             :   RelocIterator(RelocIterator&&) = default;
     383             : 
     384             :   // Iteration
     385             :   bool done() const { return done_; }
     386             :   void next();
     387             : 
     388             :   // Return pointer valid until next next().
     389             :   RelocInfo* rinfo() {
     390             :     DCHECK(!done());
     391             :     return &rinfo_;
     392             :   }
     393             : 
     394             :  private:
     395             :   RelocIterator(Code host, Address pc, Address constant_pool, const byte* pos,
     396             :                 const byte* end, int mode_mask);
     397             : 
     398             :   // Advance* moves the position before/after reading.
     399             :   // *Read* reads from current byte(s) into rinfo_.
     400             :   // *Get* just reads and returns info on current byte.
     401     1329688 :   void Advance(int bytes = 1) { pos_ -= bytes; }
     402             :   int AdvanceGetTag();
     403             :   RelocInfo::Mode GetMode();
     404             : 
     405             :   void AdvanceReadLongPCJump();
     406             : 
     407             :   void ReadShortTaggedPC();
     408             :   void ReadShortData();
     409             : 
     410             :   void AdvanceReadPC();
     411             :   void AdvanceReadInt();
     412             :   void AdvanceReadData();
     413             : 
     414             :   // If the given mode is wanted, set it in rinfo_ and return true.
     415             :   // Else return false. Used for efficiently skipping unwanted modes.
     416             :   bool SetMode(RelocInfo::Mode mode) {
     417   197078172 :     return (mode_mask_ & (1 << mode)) ? (rinfo_.rmode_ = mode, true) : false;
     418             :   }
     419             : 
     420             :   const byte* pos_;
     421             :   const byte* end_;
     422             :   RelocInfo rinfo_;
     423             :   bool done_ = false;
     424             :   const int mode_mask_;
     425             : 
     426             :   DISALLOW_COPY_AND_ASSIGN(RelocIterator);
     427             : };
     428             : 
     429             : }  // namespace internal
     430             : }  // namespace v8
     431             : 
     432             : #endif  // V8_RELOC_INFO_H_

Generated by: LCOV version 1.10