6779ee3d88b328b5dcde250ad5edc0b399df3896
[platform/upstream/nodejs.git] / deps / v8 / src / ppc / assembler-ppc-inl.h
1 // Copyright (c) 1994-2006 Sun Microsystems Inc.
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
6 // are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // - Redistribution in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the
14 // 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
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 // OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 // The original source code covered by the above license above has been modified
34 // significantly by Google Inc.
35 // Copyright 2014 the V8 project authors. All rights reserved.
36
37 #ifndef V8_PPC_ASSEMBLER_PPC_INL_H_
38 #define V8_PPC_ASSEMBLER_PPC_INL_H_
39
40 #include "src/ppc/assembler-ppc.h"
41
42 #include "src/assembler.h"
43 #include "src/debug.h"
44
45
46 namespace v8 {
47 namespace internal {
48
49
50 bool CpuFeatures::SupportsCrankshaft() { return true; }
51
52
53 void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
54 #if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
55   if (RelocInfo::IsInternalReference(rmode_)) {
56     // absolute code pointer inside code object moves with the code object.
57     Assembler::RelocateInternalReference(pc_, delta, 0, icache_flush_mode);
58   }
59 #endif
60   // We do not use pc relative addressing on PPC, so there is
61   // nothing else to do.
62 }
63
64
65 Address RelocInfo::target_address() {
66   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
67   return Assembler::target_address_at(pc_, host_);
68 }
69
70
71 Address RelocInfo::target_address_address() {
72   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) ||
73          rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
74
75 #if V8_OOL_CONSTANT_POOL
76   if (Assembler::IsConstantPoolLoadStart(pc_)) {
77     // We return the PC for ool constant pool since this function is used by the
78     // serializerer and expects the address to reside within the code object.
79     return reinterpret_cast<Address>(pc_);
80   }
81 #endif
82
83   // Read the address of the word containing the target_address in an
84   // instruction stream.
85   // The only architecture-independent user of this function is the serializer.
86   // The serializer uses it to find out how many raw bytes of instruction to
87   // output before the next target.
88   // For an instruction like LIS/ORI where the target bits are mixed into the
89   // instruction bits, the size of the target will be zero, indicating that the
90   // serializer should not step forward in memory after a target is resolved
91   // and written.
92   return reinterpret_cast<Address>(pc_);
93 }
94
95
96 Address RelocInfo::constant_pool_entry_address() {
97 #if V8_OOL_CONSTANT_POOL
98   return Assembler::target_constant_pool_address_at(pc_,
99                                                     host_->constant_pool());
100 #else
101   UNREACHABLE();
102   return NULL;
103 #endif
104 }
105
106
107 int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; }
108
109
110 void RelocInfo::set_target_address(Address target,
111                                    WriteBarrierMode write_barrier_mode,
112                                    ICacheFlushMode icache_flush_mode) {
113   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
114   Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
115   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
116       IsCodeTarget(rmode_)) {
117     Object* target_code = Code::GetCodeFromTargetAddress(target);
118     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
119         host(), this, HeapObject::cast(target_code));
120   }
121 }
122
123
124 Address Assembler::break_address_from_return_address(Address pc) {
125   return target_address_from_return_address(pc);
126 }
127
128
129 Address Assembler::target_address_from_return_address(Address pc) {
130 // Returns the address of the call target from the return address that will
131 // be returned to after a call.
132 // Call sequence is :
133 //  mov   ip, @ call address
134 //  mtlr  ip
135 //  blrl
136 //                      @ return address
137 #if V8_OOL_CONSTANT_POOL
138   if (IsConstantPoolLoadEnd(pc - 3 * kInstrSize)) {
139     return pc - (kMovInstructionsConstantPool + 2) * kInstrSize;
140   }
141 #endif
142   return pc - (kMovInstructionsNoConstantPool + 2) * kInstrSize;
143 }
144
145
146 Address Assembler::return_address_from_call_start(Address pc) {
147 #if V8_OOL_CONSTANT_POOL
148   Address load_address = pc + (kMovInstructionsConstantPool - 1) * kInstrSize;
149   if (IsConstantPoolLoadEnd(load_address))
150     return pc + (kMovInstructionsConstantPool + 2) * kInstrSize;
151 #endif
152   return pc + (kMovInstructionsNoConstantPool + 2) * kInstrSize;
153 }
154
155
156 Object* RelocInfo::target_object() {
157   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
158   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
159 }
160
161
162 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
163   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
164   return Handle<Object>(
165       reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_)));
166 }
167
168
169 void RelocInfo::set_target_object(Object* target,
170                                   WriteBarrierMode write_barrier_mode,
171                                   ICacheFlushMode icache_flush_mode) {
172   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
173   Assembler::set_target_address_at(
174       pc_, host_, reinterpret_cast<Address>(target), icache_flush_mode);
175   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
176       target->IsHeapObject()) {
177     host()->GetHeap()->incremental_marking()->RecordWrite(
178         host(), &Memory::Object_at(pc_), HeapObject::cast(target));
179   }
180 }
181
182
183 Address RelocInfo::target_reference() {
184   DCHECK(rmode_ == EXTERNAL_REFERENCE);
185   return Assembler::target_address_at(pc_, host_);
186 }
187
188
189 Address RelocInfo::target_runtime_entry(Assembler* origin) {
190   DCHECK(IsRuntimeEntry(rmode_));
191   return target_address();
192 }
193
194
195 void RelocInfo::set_target_runtime_entry(Address target,
196                                          WriteBarrierMode write_barrier_mode,
197                                          ICacheFlushMode icache_flush_mode) {
198   DCHECK(IsRuntimeEntry(rmode_));
199   if (target_address() != target)
200     set_target_address(target, write_barrier_mode, icache_flush_mode);
201 }
202
203
204 Handle<Cell> RelocInfo::target_cell_handle() {
205   DCHECK(rmode_ == RelocInfo::CELL);
206   Address address = Memory::Address_at(pc_);
207   return Handle<Cell>(reinterpret_cast<Cell**>(address));
208 }
209
210
211 Cell* RelocInfo::target_cell() {
212   DCHECK(rmode_ == RelocInfo::CELL);
213   return Cell::FromValueAddress(Memory::Address_at(pc_));
214 }
215
216
217 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode,
218                                 ICacheFlushMode icache_flush_mode) {
219   DCHECK(rmode_ == RelocInfo::CELL);
220   Address address = cell->address() + Cell::kValueOffset;
221   Memory::Address_at(pc_) = address;
222   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
223     // TODO(1550) We are passing NULL as a slot because cell can never be on
224     // evacuation candidate.
225     host()->GetHeap()->incremental_marking()->RecordWrite(host(), NULL, cell);
226   }
227 }
228
229
230 #if V8_OOL_CONSTANT_POOL
231 static const int kNoCodeAgeInstructions = 7;
232 #else
233 static const int kNoCodeAgeInstructions = 6;
234 #endif
235 static const int kCodeAgingInstructions =
236     Assembler::kMovInstructionsNoConstantPool + 3;
237 static const int kNoCodeAgeSequenceInstructions =
238     ((kNoCodeAgeInstructions >= kCodeAgingInstructions)
239          ? kNoCodeAgeInstructions
240          : kCodeAgingInstructions);
241 static const int kNoCodeAgeSequenceNops =
242     (kNoCodeAgeSequenceInstructions - kNoCodeAgeInstructions);
243 static const int kCodeAgingSequenceNops =
244     (kNoCodeAgeSequenceInstructions - kCodeAgingInstructions);
245 static const int kCodeAgingTargetDelta = 1 * Assembler::kInstrSize;
246 static const int kNoCodeAgeSequenceLength =
247     (kNoCodeAgeSequenceInstructions * Assembler::kInstrSize);
248
249
250 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
251   UNREACHABLE();  // This should never be reached on PPC.
252   return Handle<Object>();
253 }
254
255
256 Code* RelocInfo::code_age_stub() {
257   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
258   return Code::GetCodeFromTargetAddress(
259       Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_));
260 }
261
262
263 void RelocInfo::set_code_age_stub(Code* stub,
264                                   ICacheFlushMode icache_flush_mode) {
265   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
266   Assembler::set_target_address_at(pc_ + kCodeAgingTargetDelta, host_,
267                                    stub->instruction_start(),
268                                    icache_flush_mode);
269 }
270
271
272 Address RelocInfo::call_address() {
273   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
274          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
275   // The pc_ offset of 0 assumes patched return sequence per
276   // BreakLocationIterator::SetDebugBreakAtReturn(), or debug break
277   // slot per BreakLocationIterator::SetDebugBreakAtSlot().
278   return Assembler::target_address_at(pc_, host_);
279 }
280
281
282 void RelocInfo::set_call_address(Address target) {
283   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
284          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
285   Assembler::set_target_address_at(pc_, host_, target);
286   if (host() != NULL) {
287     Object* target_code = Code::GetCodeFromTargetAddress(target);
288     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
289         host(), this, HeapObject::cast(target_code));
290   }
291 }
292
293
294 Object* RelocInfo::call_object() { return *call_object_address(); }
295
296
297 void RelocInfo::set_call_object(Object* target) {
298   *call_object_address() = target;
299 }
300
301
302 Object** RelocInfo::call_object_address() {
303   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
304          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
305   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
306 }
307
308
309 void RelocInfo::WipeOut() {
310   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
311          IsRuntimeEntry(rmode_) || IsExternalReference(rmode_));
312   Assembler::set_target_address_at(pc_, host_, NULL);
313 }
314
315
316 bool RelocInfo::IsPatchedReturnSequence() {
317   //
318   // The patched return sequence is defined by
319   // BreakLocationIterator::SetDebugBreakAtReturn()
320   // FIXED_SEQUENCE
321
322   Instr instr0 = Assembler::instr_at(pc_);
323   Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
324 #if V8_TARGET_ARCH_PPC64
325   Instr instr3 = Assembler::instr_at(pc_ + (3 * Assembler::kInstrSize));
326   Instr instr4 = Assembler::instr_at(pc_ + (4 * Assembler::kInstrSize));
327   Instr binstr = Assembler::instr_at(pc_ + (7 * Assembler::kInstrSize));
328 #else
329   Instr binstr = Assembler::instr_at(pc_ + 4 * Assembler::kInstrSize);
330 #endif
331   bool patched_return =
332       ((instr0 & kOpcodeMask) == ADDIS && (instr1 & kOpcodeMask) == ORI &&
333 #if V8_TARGET_ARCH_PPC64
334        (instr3 & kOpcodeMask) == ORIS && (instr4 & kOpcodeMask) == ORI &&
335 #endif
336        (binstr == 0x7d821008));  // twge r2, r2
337
338   // printf("IsPatchedReturnSequence: %d\n", patched_return);
339   return patched_return;
340 }
341
342
343 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
344   Instr current_instr = Assembler::instr_at(pc_);
345   return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
346 }
347
348
349 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
350   RelocInfo::Mode mode = rmode();
351   if (mode == RelocInfo::EMBEDDED_OBJECT) {
352     visitor->VisitEmbeddedPointer(this);
353   } else if (RelocInfo::IsCodeTarget(mode)) {
354     visitor->VisitCodeTarget(this);
355   } else if (mode == RelocInfo::CELL) {
356     visitor->VisitCell(this);
357   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
358     visitor->VisitExternalReference(this);
359   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
360     visitor->VisitCodeAgeSequence(this);
361   } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
362               (RelocInfo::IsDebugBreakSlot(mode) &&
363                IsPatchedDebugBreakSlotSequence())) &&
364              isolate->debug()->has_break_points()) {
365     visitor->VisitDebugTarget(this);
366   } else if (IsRuntimeEntry(mode)) {
367     visitor->VisitRuntimeEntry(this);
368   }
369 }
370
371
372 template <typename StaticVisitor>
373 void RelocInfo::Visit(Heap* heap) {
374   RelocInfo::Mode mode = rmode();
375   if (mode == RelocInfo::EMBEDDED_OBJECT) {
376     StaticVisitor::VisitEmbeddedPointer(heap, this);
377   } else if (RelocInfo::IsCodeTarget(mode)) {
378     StaticVisitor::VisitCodeTarget(heap, this);
379   } else if (mode == RelocInfo::CELL) {
380     StaticVisitor::VisitCell(heap, this);
381   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
382     StaticVisitor::VisitExternalReference(this);
383   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
384     StaticVisitor::VisitCodeAgeSequence(heap, this);
385   } else if (heap->isolate()->debug()->has_break_points() &&
386              ((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
387               (RelocInfo::IsDebugBreakSlot(mode) &&
388                IsPatchedDebugBreakSlotSequence()))) {
389     StaticVisitor::VisitDebugTarget(heap, this);
390   } else if (IsRuntimeEntry(mode)) {
391     StaticVisitor::VisitRuntimeEntry(this);
392   }
393 }
394
395 Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) {
396   rm_ = no_reg;
397   imm_ = immediate;
398   rmode_ = rmode;
399 }
400
401 Operand::Operand(const ExternalReference& f) {
402   rm_ = no_reg;
403   imm_ = reinterpret_cast<intptr_t>(f.address());
404   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
405 }
406
407 Operand::Operand(Smi* value) {
408   rm_ = no_reg;
409   imm_ = reinterpret_cast<intptr_t>(value);
410   rmode_ = kRelocInfo_NONEPTR;
411 }
412
413 Operand::Operand(Register rm) {
414   rm_ = rm;
415   rmode_ = kRelocInfo_NONEPTR;  // PPC -why doesn't ARM do this?
416 }
417
418 void Assembler::CheckBuffer() {
419   if (buffer_space() <= kGap) {
420     GrowBuffer();
421   }
422 }
423
424 void Assembler::CheckTrampolinePoolQuick() {
425   if (pc_offset() >= next_buffer_check_) {
426     CheckTrampolinePool();
427   }
428 }
429
430 void Assembler::emit(Instr x) {
431   CheckBuffer();
432   *reinterpret_cast<Instr*>(pc_) = x;
433   pc_ += kInstrSize;
434   CheckTrampolinePoolQuick();
435 }
436
437 bool Operand::is_reg() const { return rm_.is_valid(); }
438
439
440 // Fetch the 32bit value from the FIXED_SEQUENCE lis/ori
441 Address Assembler::target_address_at(Address pc,
442                                      ConstantPoolArray* constant_pool) {
443   Instr instr1 = instr_at(pc);
444   Instr instr2 = instr_at(pc + kInstrSize);
445   // Interpret 2 instructions generated by lis/ori
446   if (IsLis(instr1) && IsOri(instr2)) {
447 #if V8_TARGET_ARCH_PPC64
448     Instr instr4 = instr_at(pc + (3 * kInstrSize));
449     Instr instr5 = instr_at(pc + (4 * kInstrSize));
450     // Assemble the 64 bit value.
451     uint64_t hi = (static_cast<uint32_t>((instr1 & kImm16Mask) << 16) |
452                    static_cast<uint32_t>(instr2 & kImm16Mask));
453     uint64_t lo = (static_cast<uint32_t>((instr4 & kImm16Mask) << 16) |
454                    static_cast<uint32_t>(instr5 & kImm16Mask));
455     return reinterpret_cast<Address>((hi << 32) | lo);
456 #else
457     // Assemble the 32 bit value.
458     return reinterpret_cast<Address>(((instr1 & kImm16Mask) << 16) |
459                                      (instr2 & kImm16Mask));
460 #endif
461   }
462 #if V8_OOL_CONSTANT_POOL
463   return Memory::Address_at(target_constant_pool_address_at(pc, constant_pool));
464 #else
465   DCHECK(false);
466   return (Address)0;
467 #endif
468 }
469
470
471 #if V8_OOL_CONSTANT_POOL
472 bool Assembler::IsConstantPoolLoadStart(Address pc) {
473 #if V8_TARGET_ARCH_PPC64
474   if (!IsLi(instr_at(pc))) return false;
475   pc += kInstrSize;
476 #endif
477   return GetRA(instr_at(pc)).is(kConstantPoolRegister);
478 }
479
480
481 bool Assembler::IsConstantPoolLoadEnd(Address pc) {
482 #if V8_TARGET_ARCH_PPC64
483   pc -= kInstrSize;
484 #endif
485   return IsConstantPoolLoadStart(pc);
486 }
487
488
489 int Assembler::GetConstantPoolOffset(Address pc) {
490   DCHECK(IsConstantPoolLoadStart(pc));
491   Instr instr = instr_at(pc);
492   int offset = SIGN_EXT_IMM16((instr & kImm16Mask));
493   return offset;
494 }
495
496
497 void Assembler::SetConstantPoolOffset(Address pc, int offset) {
498   DCHECK(IsConstantPoolLoadStart(pc));
499   DCHECK(is_int16(offset));
500   Instr instr = instr_at(pc);
501   instr &= ~kImm16Mask;
502   instr |= (offset & kImm16Mask);
503   instr_at_put(pc, instr);
504 }
505
506
507 Address Assembler::target_constant_pool_address_at(
508     Address pc, ConstantPoolArray* constant_pool) {
509   Address addr = reinterpret_cast<Address>(constant_pool);
510   DCHECK(addr);
511   addr += GetConstantPoolOffset(pc);
512   return addr;
513 }
514 #endif
515
516
517 // This sets the branch destination (which gets loaded at the call address).
518 // This is for calls and branches within generated code.  The serializer
519 // has already deserialized the mov instructions etc.
520 // There is a FIXED_SEQUENCE assumption here
521 void Assembler::deserialization_set_special_target_at(
522     Address instruction_payload, Code* code, Address target) {
523   set_target_address_at(instruction_payload, code, target);
524 }
525
526 // This code assumes the FIXED_SEQUENCE of lis/ori
527 void Assembler::set_target_address_at(Address pc,
528                                       ConstantPoolArray* constant_pool,
529                                       Address target,
530                                       ICacheFlushMode icache_flush_mode) {
531   Instr instr1 = instr_at(pc);
532   Instr instr2 = instr_at(pc + kInstrSize);
533   // Interpret 2 instructions generated by lis/ori
534   if (IsLis(instr1) && IsOri(instr2)) {
535 #if V8_TARGET_ARCH_PPC64
536     Instr instr4 = instr_at(pc + (3 * kInstrSize));
537     Instr instr5 = instr_at(pc + (4 * kInstrSize));
538     // Needs to be fixed up when mov changes to handle 64-bit values.
539     uint32_t* p = reinterpret_cast<uint32_t*>(pc);
540     uintptr_t itarget = reinterpret_cast<uintptr_t>(target);
541
542     instr5 &= ~kImm16Mask;
543     instr5 |= itarget & kImm16Mask;
544     itarget = itarget >> 16;
545
546     instr4 &= ~kImm16Mask;
547     instr4 |= itarget & kImm16Mask;
548     itarget = itarget >> 16;
549
550     instr2 &= ~kImm16Mask;
551     instr2 |= itarget & kImm16Mask;
552     itarget = itarget >> 16;
553
554     instr1 &= ~kImm16Mask;
555     instr1 |= itarget & kImm16Mask;
556     itarget = itarget >> 16;
557
558     *p = instr1;
559     *(p + 1) = instr2;
560     *(p + 3) = instr4;
561     *(p + 4) = instr5;
562     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
563       CpuFeatures::FlushICache(p, 5 * kInstrSize);
564     }
565 #else
566     uint32_t* p = reinterpret_cast<uint32_t*>(pc);
567     uint32_t itarget = reinterpret_cast<uint32_t>(target);
568     int lo_word = itarget & kImm16Mask;
569     int hi_word = itarget >> 16;
570     instr1 &= ~kImm16Mask;
571     instr1 |= hi_word;
572     instr2 &= ~kImm16Mask;
573     instr2 |= lo_word;
574
575     *p = instr1;
576     *(p + 1) = instr2;
577     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
578       CpuFeatures::FlushICache(p, 2 * kInstrSize);
579     }
580 #endif
581   } else {
582 #if V8_OOL_CONSTANT_POOL
583     Memory::Address_at(target_constant_pool_address_at(pc, constant_pool)) =
584         target;
585 #else
586     UNREACHABLE();
587 #endif
588   }
589 }
590 }
591 }  // namespace v8::internal
592
593 #endif  // V8_PPC_ASSEMBLER_PPC_INL_H_