1 // Copyright 2013, ARM Limited 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #ifndef jit_arm64_vixl_MozBaseAssembler_vixl_h 28 #define jit_arm64_vixl_MozBaseAssembler_vixl_h 29 30 #include "jit/arm64/vixl/Constants-vixl.h" 31 #include "jit/arm64/vixl/Instructions-vixl.h" 32 33 #include "jit/shared/Assembler-shared.h" 34 #include "jit/shared/IonAssemblerBufferWithConstantPools.h" 35 36 namespace vixl { 37 38 39 using js::jit::BufferOffset; 40 41 42 class MozBaseAssembler; 43 typedef js::jit::AssemblerBufferWithConstantPools<1024, 4, Instruction, MozBaseAssembler, 44 NumShortBranchRangeTypes> ARMBuffer; 45 46 // Base class for vixl::Assembler, for isolating Moz-specific changes to VIXL. 47 class MozBaseAssembler : public js::jit::AssemblerShared { 48 // Buffer initialization constants. 49 static const unsigned BufferGuardSize = 1; 50 static const unsigned BufferHeaderSize = 1; 51 static const size_t BufferCodeAlignment = 8; 52 static const size_t BufferMaxPoolOffset = 1024; 53 static const unsigned BufferPCBias = 0; 54 static const uint32_t BufferAlignmentFillInstruction = BRK | (0xdead << ImmException_offset); 55 static const uint32_t BufferNopFillInstruction = HINT | (31 << Rt_offset); 56 static const unsigned BufferNumDebugNopsToInsert = 0; 57 58 public: MozBaseAssembler()59 MozBaseAssembler() 60 : armbuffer_(BufferGuardSize, 61 BufferHeaderSize, 62 BufferCodeAlignment, 63 BufferMaxPoolOffset, 64 BufferPCBias, 65 BufferAlignmentFillInstruction, 66 BufferNopFillInstruction, 67 BufferNumDebugNopsToInsert) 68 { } 69 70 public: 71 // Helper function for use with the ARMBuffer. 72 // The MacroAssembler must create an AutoJitContextAlloc before initializing the buffer. initWithAllocator()73 void initWithAllocator() { 74 armbuffer_.initWithAllocator(); 75 } 76 77 // Return the Instruction at a given byte offset. getInstructionAt(BufferOffset offset)78 Instruction* getInstructionAt(BufferOffset offset) { 79 return armbuffer_.getInst(offset); 80 } 81 82 // Return the byte offset of a bound label. 83 template <typename T> GetLabelByteOffset(const js::jit::Label * label)84 inline T GetLabelByteOffset(const js::jit::Label* label) { 85 VIXL_ASSERT(label->bound()); 86 JS_STATIC_ASSERT(sizeof(T) >= sizeof(uint32_t)); 87 return reinterpret_cast<T>(label->offset()); 88 } 89 90 protected: 91 // Get the buffer offset of the next inserted instruction. This may flush 92 // constant pools. nextInstrOffset()93 BufferOffset nextInstrOffset() { 94 return armbuffer_.nextInstrOffset(); 95 } 96 97 // Get the next usable buffer offset. Note that a constant pool may be placed 98 // here before the next instruction is emitted. nextOffset()99 BufferOffset nextOffset() const { 100 return armbuffer_.nextOffset(); 101 } 102 103 // Allocate memory in the buffer by forwarding to armbuffer_. 104 // Propagate OOM errors. 105 BufferOffset allocEntry(size_t numInst, unsigned numPoolEntries, 106 uint8_t* inst, uint8_t* data, 107 ARMBuffer::PoolEntry* pe = nullptr, 108 bool markAsBranch = false) 109 { 110 BufferOffset offset = armbuffer_.allocEntry(numInst, numPoolEntries, inst, 111 data, pe, markAsBranch); 112 propagateOOM(offset.assigned()); 113 return offset; 114 } 115 116 // Emit the instruction, returning its offset. 117 BufferOffset Emit(Instr instruction, bool isBranch = false) { 118 JS_STATIC_ASSERT(sizeof(instruction) == kInstructionSize); 119 return armbuffer_.putInt(*(uint32_t*)(&instruction), isBranch); 120 } 121 EmitBranch(Instr instruction)122 BufferOffset EmitBranch(Instr instruction) { 123 return Emit(instruction, true); 124 } 125 126 public: 127 // Emit the instruction at |at|. Emit(Instruction * at,Instr instruction)128 static void Emit(Instruction* at, Instr instruction) { 129 JS_STATIC_ASSERT(sizeof(instruction) == kInstructionSize); 130 memcpy(at, &instruction, sizeof(instruction)); 131 } 132 EmitBranch(Instruction * at,Instr instruction)133 static void EmitBranch(Instruction* at, Instr instruction) { 134 // TODO: Assert that the buffer already has the instruction marked as a branch. 135 Emit(at, instruction); 136 } 137 138 // Emit data inline in the instruction stream. EmitData(void const * data,unsigned size)139 BufferOffset EmitData(void const * data, unsigned size) { 140 VIXL_ASSERT(size % 4 == 0); 141 return armbuffer_.allocEntry(size / sizeof(uint32_t), 0, (uint8_t*)(data), nullptr); 142 } 143 144 public: 145 // Size of the code generated in bytes, including pools. SizeOfCodeGenerated()146 size_t SizeOfCodeGenerated() const { 147 return armbuffer_.size(); 148 } 149 150 // Move the pool into the instruction stream. flushBuffer()151 void flushBuffer() { 152 armbuffer_.flushPool(); 153 } 154 155 // Inhibit pool flushing for the given number of instructions. 156 // Generating more than |maxInst| instructions in a no-pool region 157 // triggers an assertion within the ARMBuffer. 158 // Does not nest. enterNoPool(size_t maxInst)159 void enterNoPool(size_t maxInst) { 160 armbuffer_.enterNoPool(maxInst); 161 } 162 163 // Marks the end of a no-pool region. leaveNoPool()164 void leaveNoPool() { 165 armbuffer_.leaveNoPool(); 166 } 167 168 public: 169 // Static interface used by IonAssemblerBufferWithConstantPools. 170 static void InsertIndexIntoTag(uint8_t* load, uint32_t index); 171 static bool PatchConstantPoolLoad(void* loadAddr, void* constPoolAddr); 172 static void PatchShortRangeBranchToVeneer(ARMBuffer*, unsigned rangeIdx, BufferOffset deadline, 173 BufferOffset veneer); 174 static uint32_t PlaceConstantPoolBarrier(int offset); 175 176 static void WritePoolHeader(uint8_t* start, js::jit::Pool* p, bool isNatural); 177 static void WritePoolFooter(uint8_t* start, js::jit::Pool* p, bool isNatural); 178 static void WritePoolGuard(BufferOffset branch, Instruction* inst, BufferOffset dest); 179 180 static ptrdiff_t GetBranchOffset(const Instruction* i); 181 static void RetargetNearBranch(Instruction* i, int offset, Condition cond, bool final = true); 182 static void RetargetNearBranch(Instruction* i, int offset, bool final = true); 183 static void RetargetFarBranch(Instruction* i, uint8_t** slot, uint8_t* dest, Condition cond); 184 185 protected: 186 // Functions for managing Labels and linked lists of Label uses. 187 188 // Get the next Label user in the linked list of Label uses. 189 // Return an unassigned BufferOffset when the end of the list is reached. 190 BufferOffset NextLink(BufferOffset cur); 191 192 // Patch the instruction at cur to link to the instruction at next. 193 void SetNextLink(BufferOffset cur, BufferOffset next); 194 195 // Link the current (not-yet-emitted) instruction to the specified label, 196 // then return a raw offset to be encoded in the instruction. 197 ptrdiff_t LinkAndGetByteOffsetTo(BufferOffset branch, js::jit::Label* label); 198 ptrdiff_t LinkAndGetInstructionOffsetTo(BufferOffset branch, ImmBranchRangeType branchRange, 199 js::jit::Label* label); 200 ptrdiff_t LinkAndGetPageOffsetTo(BufferOffset branch, js::jit::Label* label); 201 202 // A common implementation for the LinkAndGet<Type>OffsetTo helpers. 203 ptrdiff_t LinkAndGetOffsetTo(BufferOffset branch, ImmBranchRangeType branchRange, 204 unsigned elementSizeBits, js::jit::Label* label); 205 206 protected: 207 // The buffer into which code and relocation info are generated. 208 ARMBuffer armbuffer_; 209 }; 210 211 212 } // namespace vixl 213 214 215 #endif // jit_arm64_vixl_MozBaseAssembler_vixl_h 216 217