1 
2 // Copyright (c) 1994-2006 Sun Microsystems Inc.
3 // All Rights Reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // - Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 //
12 // - Redistribution in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 // - Neither the name of Sun Microsystems or the names of contributors may
17 // be used to endorse or promote products derived from this software without
18 // specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 
32 // The original source code covered by the above license above has been
33 // modified significantly by Google Inc.
34 // Copyright 2012 the V8 project authors. All rights reserved.
35 
36 
37 #ifndef V8_MIPS_ASSEMBLER_MIPS_INL_H_
38 #define V8_MIPS_ASSEMBLER_MIPS_INL_H_
39 
40 #include "src/mips/assembler-mips.h"
41 
42 #include "src/assembler.h"
43 #include "src/debug/debug.h"
44 #include "src/objects-inl.h"
45 
46 namespace v8 {
47 namespace internal {
48 
SupportsOptimizer()49 bool CpuFeatures::SupportsOptimizer() { return IsSupported(FPU); }
50 
SupportsWasmSimd128()51 bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(MIPS_SIMD); }
52 
53 // -----------------------------------------------------------------------------
54 // Operand and MemOperand.
55 
is_reg()56 bool Operand::is_reg() const {
57   return rm_.is_valid();
58 }
59 
immediate()60 int32_t Operand::immediate() const {
61   DCHECK(!is_reg());
62   DCHECK(!IsHeapObjectRequest());
63   return value_.immediate;
64 }
65 
66 // -----------------------------------------------------------------------------
67 // RelocInfo.
68 
apply(intptr_t delta)69 void RelocInfo::apply(intptr_t delta) {
70   if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) {
71     // Absolute code pointer inside code object moves with the code object.
72     Assembler::RelocateInternalReference(rmode_, pc_, delta);
73   }
74 }
75 
76 
target_address()77 Address RelocInfo::target_address() {
78   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_));
79   return Assembler::target_address_at(pc_, constant_pool_);
80 }
81 
target_address_address()82 Address RelocInfo::target_address_address() {
83   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
84          IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
85          IsOffHeapTarget(rmode_));
86   // Read the address of the word containing the target_address in an
87   // instruction stream.
88   // The only architecture-independent user of this function is the serializer.
89   // The serializer uses it to find out how many raw bytes of instruction to
90   // output before the next target.
91   // For an instruction like LUI/ORI where the target bits are mixed into the
92   // instruction bits, the size of the target will be zero, indicating that the
93   // serializer should not step forward in memory after a target is resolved
94   // and written. In this case the target_address_address function should
95   // return the end of the instructions to be patched, allowing the
96   // deserializer to deserialize the instructions as raw bytes and put them in
97   // place, ready to be patched with the target. After jump optimization,
98   // that is the address of the instruction that follows J/JAL/JR/JALR
99   // instruction.
100   if (IsMipsArchVariant(kMips32r6)) {
101     // On R6 we don't move to the end of the instructions to be patched, but one
102     // instruction before, because if these instructions are at the end of the
103     // code object it can cause errors in the deserializer.
104     return pc_ + (Assembler::kInstructionsFor32BitConstant - 1) * kInstrSize;
105   } else {
106     return pc_ + Assembler::kInstructionsFor32BitConstant * kInstrSize;
107   }
108 }
109 
constant_pool_entry_address()110 Address RelocInfo::constant_pool_entry_address() {
111   UNREACHABLE();
112 }
113 
114 
target_address_size()115 int RelocInfo::target_address_size() {
116   return Assembler::kSpecialTargetSize;
117 }
118 
target_address_from_return_address(Address pc)119 Address Assembler::target_address_from_return_address(Address pc) {
120   return pc - kCallTargetAddressOffset;
121 }
122 
deserialization_set_special_target_at(Address instruction_payload,Code * code,Address target)123 void Assembler::deserialization_set_special_target_at(
124     Address instruction_payload, Code* code, Address target) {
125   if (IsMipsArchVariant(kMips32r6)) {
126     // On R6 the address location is shifted by one instruction
127     set_target_address_at(
128         instruction_payload - (kInstructionsFor32BitConstant - 1) * kInstrSize,
129         code ? code->constant_pool() : kNullAddress, target);
130   } else {
131     set_target_address_at(
132         instruction_payload - kInstructionsFor32BitConstant * kInstrSize,
133         code ? code->constant_pool() : kNullAddress, target);
134   }
135 }
136 
deserialization_special_target_size(Address instruction_payload)137 int Assembler::deserialization_special_target_size(
138     Address instruction_payload) {
139   return kSpecialTargetSize;
140 }
141 
set_target_internal_reference_encoded_at(Address pc,Address target)142 void Assembler::set_target_internal_reference_encoded_at(Address pc,
143                                                          Address target) {
144   Instr instr1 = Assembler::instr_at(pc + 0 * kInstrSize);
145   Instr instr2 = Assembler::instr_at(pc + 1 * kInstrSize);
146   DCHECK(Assembler::IsLui(instr1));
147   DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
148   instr1 &= ~kImm16Mask;
149   instr2 &= ~kImm16Mask;
150   int32_t imm = static_cast<int32_t>(target);
151   DCHECK_EQ(imm & 3, 0);
152   if (Assembler::IsJicOrJialc(instr2)) {
153     // Encoded internal references are lui/jic load of 32-bit absolute address.
154     uint32_t lui_offset_u, jic_offset_u;
155     Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
156 
157     Assembler::instr_at_put(pc + 0 * kInstrSize, instr1 | lui_offset_u);
158     Assembler::instr_at_put(pc + 1 * kInstrSize, instr2 | jic_offset_u);
159   } else {
160     // Encoded internal references are lui/ori load of 32-bit absolute address.
161     Assembler::instr_at_put(pc + 0 * kInstrSize,
162                             instr1 | ((imm >> kLuiShift) & kImm16Mask));
163     Assembler::instr_at_put(pc + 1 * kInstrSize, instr2 | (imm & kImm16Mask));
164   }
165 
166   // Currently used only by deserializer, and all code will be flushed
167   // after complete deserialization, no need to flush on each reference.
168 }
169 
deserialization_set_target_internal_reference_at(Address pc,Address target,RelocInfo::Mode mode)170 void Assembler::deserialization_set_target_internal_reference_at(
171     Address pc, Address target, RelocInfo::Mode mode) {
172   if (mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
173     DCHECK(IsLui(instr_at(pc)));
174     set_target_internal_reference_encoded_at(pc, target);
175   } else {
176     DCHECK(mode == RelocInfo::INTERNAL_REFERENCE);
177     Memory<Address>(pc) = target;
178   }
179 }
180 
target_object()181 HeapObject* RelocInfo::target_object() {
182   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
183   return HeapObject::cast(reinterpret_cast<Object*>(
184       Assembler::target_address_at(pc_, constant_pool_)));
185 }
186 
target_object_handle(Assembler * origin)187 Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) {
188   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
189   return Handle<HeapObject>(reinterpret_cast<HeapObject**>(
190       Assembler::target_address_at(pc_, constant_pool_)));
191 }
192 
set_target_object(Heap * heap,HeapObject * target,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)193 void RelocInfo::set_target_object(Heap* heap, HeapObject* target,
194                                   WriteBarrierMode write_barrier_mode,
195                                   ICacheFlushMode icache_flush_mode) {
196   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
197   Assembler::set_target_address_at(pc_, constant_pool_,
198                                    reinterpret_cast<Address>(target),
199                                    icache_flush_mode);
200   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) {
201     WriteBarrierForCode(host(), this, target);
202   }
203 }
204 
205 
target_external_reference()206 Address RelocInfo::target_external_reference() {
207   DCHECK(rmode_ == EXTERNAL_REFERENCE);
208   return Assembler::target_address_at(pc_, constant_pool_);
209 }
210 
set_target_external_reference(Address target,ICacheFlushMode icache_flush_mode)211 void RelocInfo::set_target_external_reference(
212     Address target, ICacheFlushMode icache_flush_mode) {
213   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
214   Assembler::set_target_address_at(pc_, constant_pool_, target,
215                                    icache_flush_mode);
216 }
217 
target_internal_reference()218 Address RelocInfo::target_internal_reference() {
219   if (rmode_ == INTERNAL_REFERENCE) {
220     return Memory<Address>(pc_);
221   } else {
222     // Encoded internal references are lui/ori or lui/jic load of 32-bit
223     // absolute address.
224     DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
225     Instr instr1 = Assembler::instr_at(pc_ + 0 * kInstrSize);
226     Instr instr2 = Assembler::instr_at(pc_ + 1 * kInstrSize);
227     DCHECK(Assembler::IsLui(instr1));
228     DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
229     if (Assembler::IsJicOrJialc(instr2)) {
230       return static_cast<Address>(
231           Assembler::CreateTargetAddress(instr1, instr2));
232     }
233     int32_t imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
234     imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
235     return static_cast<Address>(imm);
236   }
237 }
238 
239 
target_internal_reference_address()240 Address RelocInfo::target_internal_reference_address() {
241   DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED);
242   return pc_;
243 }
244 
target_runtime_entry(Assembler * origin)245 Address RelocInfo::target_runtime_entry(Assembler* origin) {
246   DCHECK(IsRuntimeEntry(rmode_));
247   return target_address();
248 }
249 
set_target_runtime_entry(Address target,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)250 void RelocInfo::set_target_runtime_entry(Address target,
251                                          WriteBarrierMode write_barrier_mode,
252                                          ICacheFlushMode icache_flush_mode) {
253   DCHECK(IsRuntimeEntry(rmode_));
254   if (target_address() != target)
255     set_target_address(target, write_barrier_mode, icache_flush_mode);
256 }
257 
target_off_heap_target()258 Address RelocInfo::target_off_heap_target() {
259   DCHECK(IsOffHeapTarget(rmode_));
260   return Assembler::target_address_at(pc_, constant_pool_);
261 }
262 
WipeOut()263 void RelocInfo::WipeOut() {
264   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
265          IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
266          IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) ||
267          IsOffHeapTarget(rmode_));
268   if (IsInternalReference(rmode_)) {
269     Memory<Address>(pc_) = kNullAddress;
270   } else if (IsInternalReferenceEncoded(rmode_)) {
271     Assembler::set_target_internal_reference_encoded_at(pc_, kNullAddress);
272   } else {
273     Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress);
274   }
275 }
276 
277 template <typename ObjectVisitor>
Visit(ObjectVisitor * visitor)278 void RelocInfo::Visit(ObjectVisitor* visitor) {
279   RelocInfo::Mode mode = rmode();
280   if (mode == RelocInfo::EMBEDDED_OBJECT) {
281     visitor->VisitEmbeddedPointer(host(), this);
282   } else if (RelocInfo::IsCodeTargetMode(mode)) {
283     visitor->VisitCodeTarget(host(), this);
284   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
285     visitor->VisitExternalReference(host(), this);
286   } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
287              mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
288     visitor->VisitInternalReference(host(), this);
289   } else if (RelocInfo::IsRuntimeEntry(mode)) {
290     visitor->VisitRuntimeEntry(host(), this);
291   } else if (RelocInfo::IsOffHeapTarget(mode)) {
292     visitor->VisitOffHeapTarget(host(), this);
293   }
294 }
295 
296 // -----------------------------------------------------------------------------
297 // Assembler.
298 
299 
CheckBuffer()300 void Assembler::CheckBuffer() {
301   if (buffer_space() <= kGap) {
302     GrowBuffer();
303   }
304 }
305 
306 
CheckForEmitInForbiddenSlot()307 void Assembler::CheckForEmitInForbiddenSlot() {
308   if (!is_buffer_growth_blocked()) {
309     CheckBuffer();
310   }
311   if (IsPrevInstrCompactBranch()) {
312     // Nop instruction to precede a CTI in forbidden slot:
313     Instr nop = SPECIAL | SLL;
314     *reinterpret_cast<Instr*>(pc_) = nop;
315     pc_ += kInstrSize;
316 
317     ClearCompactBranchState();
318   }
319 }
320 
321 
EmitHelper(Instr x,CompactBranchType is_compact_branch)322 void Assembler::EmitHelper(Instr x, CompactBranchType is_compact_branch) {
323   if (IsPrevInstrCompactBranch()) {
324     if (Instruction::IsForbiddenAfterBranchInstr(x)) {
325       // Nop instruction to precede a CTI in forbidden slot:
326       Instr nop = SPECIAL | SLL;
327       *reinterpret_cast<Instr*>(pc_) = nop;
328       pc_ += kInstrSize;
329     }
330     ClearCompactBranchState();
331   }
332   *reinterpret_cast<Instr*>(pc_) = x;
333   pc_ += kInstrSize;
334   if (is_compact_branch == CompactBranchType::COMPACT_BRANCH) {
335     EmittedCompactBranchInstruction();
336   }
337   CheckTrampolinePoolQuick();
338 }
339 
340 template <>
341 inline void Assembler::EmitHelper(uint8_t x);
342 
343 template <typename T>
EmitHelper(T x)344 void Assembler::EmitHelper(T x) {
345   *reinterpret_cast<T*>(pc_) = x;
346   pc_ += sizeof(x);
347   CheckTrampolinePoolQuick();
348 }
349 
350 template <>
EmitHelper(uint8_t x)351 void Assembler::EmitHelper(uint8_t x) {
352   *reinterpret_cast<uint8_t*>(pc_) = x;
353   pc_ += sizeof(x);
354   if (reinterpret_cast<intptr_t>(pc_) % kInstrSize == 0) {
355     CheckTrampolinePoolQuick();
356   }
357 }
358 
emit(Instr x,CompactBranchType is_compact_branch)359 void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
360   if (!is_buffer_growth_blocked()) {
361     CheckBuffer();
362   }
363   EmitHelper(x, is_compact_branch);
364 }
365 
EnsureSpace(Assembler * assembler)366 EnsureSpace::EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
367 
368 }  // namespace internal
369 }  // namespace v8
370 
371 #endif  // V8_MIPS_ASSEMBLER_MIPS_INL_H_
372