• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
34 // modified significantly by Google Inc.
35 // Copyright 2014 the V8 project authors. All rights reserved.
36 
37 #include "src/s390/assembler-s390.h"
38 #include <sys/auxv.h>
39 #include <set>
40 #include <string>
41 
42 #if V8_TARGET_ARCH_S390
43 
44 #if V8_HOST_ARCH_S390
45 #include <elf.h>  // Required for auxv checks for STFLE support
46 #endif
47 
48 #include "src/base/bits.h"
49 #include "src/base/cpu.h"
50 #include "src/code-stubs.h"
51 #include "src/deoptimizer.h"
52 #include "src/macro-assembler.h"
53 #include "src/s390/assembler-s390-inl.h"
54 
55 namespace v8 {
56 namespace internal {
57 
58 // Get the CPU features enabled by the build.
CpuFeaturesImpliedByCompiler()59 static unsigned CpuFeaturesImpliedByCompiler() {
60   unsigned answer = 0;
61   return answer;
62 }
63 
supportsCPUFeature(const char * feature)64 static bool supportsCPUFeature(const char* feature) {
65   static std::set<std::string> features;
66   static std::set<std::string> all_available_features = {
67       "iesan3", "zarch",  "stfle",    "msa", "ldisp", "eimm",
68       "dfp",    "etf3eh", "highgprs", "te",  "vx"};
69   if (features.empty()) {
70 #if V8_HOST_ARCH_S390
71 
72 #ifndef HWCAP_S390_VX
73 #define HWCAP_S390_VX 2048
74 #endif
75 #define CHECK_AVAILABILITY_FOR(mask, value) \
76   if (f & mask) features.insert(value);
77 
78     // initialize feature vector
79     uint64_t f = getauxval(AT_HWCAP);
80     CHECK_AVAILABILITY_FOR(HWCAP_S390_ESAN3, "iesan3")
81     CHECK_AVAILABILITY_FOR(HWCAP_S390_ZARCH, "zarch")
82     CHECK_AVAILABILITY_FOR(HWCAP_S390_STFLE, "stfle")
83     CHECK_AVAILABILITY_FOR(HWCAP_S390_MSA, "msa")
84     CHECK_AVAILABILITY_FOR(HWCAP_S390_LDISP, "ldisp")
85     CHECK_AVAILABILITY_FOR(HWCAP_S390_EIMM, "eimm")
86     CHECK_AVAILABILITY_FOR(HWCAP_S390_DFP, "dfp")
87     CHECK_AVAILABILITY_FOR(HWCAP_S390_ETF3EH, "etf3eh")
88     CHECK_AVAILABILITY_FOR(HWCAP_S390_HIGH_GPRS, "highgprs")
89     CHECK_AVAILABILITY_FOR(HWCAP_S390_TE, "te")
90     CHECK_AVAILABILITY_FOR(HWCAP_S390_VX, "vx")
91 #else
92     // import all features
93     features.insert(all_available_features.begin(),
94                     all_available_features.end());
95 #endif
96   }
97   USE(all_available_features);
98   return features.find(feature) != features.end();
99 }
100 
101 // Check whether Store Facility STFLE instruction is available on the platform.
102 // Instruction returns a bit vector of the enabled hardware facilities.
supportsSTFLE()103 static bool supportsSTFLE() {
104 #if V8_HOST_ARCH_S390
105   static bool read_tried = false;
106   static uint32_t auxv_hwcap = 0;
107 
108   if (!read_tried) {
109     // Open the AUXV (auxiliary vector) pseudo-file
110     int fd = open("/proc/self/auxv", O_RDONLY);
111 
112     read_tried = true;
113     if (fd != -1) {
114 #if V8_TARGET_ARCH_S390X
115       static Elf64_auxv_t buffer[16];
116       Elf64_auxv_t* auxv_element;
117 #else
118       static Elf32_auxv_t buffer[16];
119       Elf32_auxv_t* auxv_element;
120 #endif
121       int bytes_read = 0;
122       while (bytes_read >= 0) {
123         // Read a chunk of the AUXV
124         bytes_read = read(fd, buffer, sizeof(buffer));
125         // Locate and read the platform field of AUXV if it is in the chunk
126         for (auxv_element = buffer;
127              auxv_element + sizeof(auxv_element) <= buffer + bytes_read &&
128              auxv_element->a_type != AT_NULL;
129              auxv_element++) {
130           // We are looking for HWCAP entry in AUXV to search for STFLE support
131           if (auxv_element->a_type == AT_HWCAP) {
132             /* Note: Both auxv_hwcap and buffer are static */
133             auxv_hwcap = auxv_element->a_un.a_val;
134             goto done_reading;
135           }
136         }
137       }
138     done_reading:
139       close(fd);
140     }
141   }
142 
143   // Did not find result
144   if (0 == auxv_hwcap) {
145     return false;
146   }
147 
148   // HWCAP_S390_STFLE is defined to be 4 in include/asm/elf.h.  Currently
149   // hardcoded in case that include file does not exist.
150   const uint32_t _HWCAP_S390_STFLE = 4;
151   return (auxv_hwcap & _HWCAP_S390_STFLE);
152 #else
153   // STFLE is not available on non-s390 hosts
154   return false;
155 #endif
156 }
157 
ProbeImpl(bool cross_compile)158 void CpuFeatures::ProbeImpl(bool cross_compile) {
159   supported_ |= CpuFeaturesImpliedByCompiler();
160   icache_line_size_ = 256;
161 
162   // Only use statically determined features for cross compile (snapshot).
163   if (cross_compile) return;
164 
165 #ifdef DEBUG
166   initialized_ = true;
167 #endif
168 
169   static bool performSTFLE = supportsSTFLE();
170 
171 // Need to define host, as we are generating inlined S390 assembly to test
172 // for facilities.
173 #if V8_HOST_ARCH_S390
174   if (performSTFLE) {
175     // STFLE D(B) requires:
176     //    GPR0 to specify # of double words to update minus 1.
177     //      i.e. GPR0 = 0 for 1 doubleword
178     //    D(B) to specify to memory location to store the facilities bits
179     // The facilities we are checking for are:
180     //   Bit 45 - Distinct Operands for instructions like ARK, SRK, etc.
181     // As such, we require only 1 double word
182     int64_t facilities[3] = {0L};
183     // LHI sets up GPR0
184     // STFLE is specified as .insn, as opcode is not recognized.
185     // We register the instructions kill r0 (LHI) and the CC (STFLE).
186     asm volatile(
187         "lhi   0,2\n"
188         ".insn s,0xb2b00000,%0\n"
189         : "=Q"(facilities)
190         :
191         : "cc", "r0");
192 
193     uint64_t one = static_cast<uint64_t>(1);
194     // Test for Distinct Operands Facility - Bit 45
195     if (facilities[0] & (one << (63 - 45))) {
196       supported_ |= (1u << DISTINCT_OPS);
197     }
198     // Test for General Instruction Extension Facility - Bit 34
199     if (facilities[0] & (one << (63 - 34))) {
200       supported_ |= (1u << GENERAL_INSTR_EXT);
201     }
202     // Test for Floating Point Extension Facility - Bit 37
203     if (facilities[0] & (one << (63 - 37))) {
204       supported_ |= (1u << FLOATING_POINT_EXT);
205     }
206     // Test for Vector Facility - Bit 129
207     if (facilities[2] & (one << (63 - (129 - 128))) &&
208         supportsCPUFeature("vx")) {
209       supported_ |= (1u << VECTOR_FACILITY);
210     }
211     // Test for Miscellaneous Instruction Extension Facility - Bit 58
212     if (facilities[0] & (1lu << (63 - 58))) {
213       supported_ |= (1u << MISC_INSTR_EXT2);
214     }
215   }
216 #else
217   // All distinct ops instructions can be simulated
218   supported_ |= (1u << DISTINCT_OPS);
219   // RISBG can be simulated
220   supported_ |= (1u << GENERAL_INSTR_EXT);
221   supported_ |= (1u << FLOATING_POINT_EXT);
222   supported_ |= (1u << MISC_INSTR_EXT2);
223   USE(performSTFLE);  // To avoid assert
224   USE(supportsCPUFeature);
225   supported_ |= (1u << VECTOR_FACILITY);
226 #endif
227   supported_ |= (1u << FPU);
228 }
229 
PrintTarget()230 void CpuFeatures::PrintTarget() {
231   const char* s390_arch = nullptr;
232 
233 #if V8_TARGET_ARCH_S390X
234   s390_arch = "s390x";
235 #else
236   s390_arch = "s390";
237 #endif
238 
239   printf("target %s\n", s390_arch);
240 }
241 
PrintFeatures()242 void CpuFeatures::PrintFeatures() {
243   printf("FPU=%d\n", CpuFeatures::IsSupported(FPU));
244   printf("FPU_EXT=%d\n", CpuFeatures::IsSupported(FLOATING_POINT_EXT));
245   printf("GENERAL_INSTR=%d\n", CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
246   printf("DISTINCT_OPS=%d\n", CpuFeatures::IsSupported(DISTINCT_OPS));
247   printf("VECTOR_FACILITY=%d\n", CpuFeatures::IsSupported(VECTOR_FACILITY));
248   printf("MISC_INSTR_EXT2=%d\n", CpuFeatures::IsSupported(MISC_INSTR_EXT2));
249 }
250 
ToRegister(int num)251 Register ToRegister(int num) {
252   DCHECK(num >= 0 && num < kNumRegisters);
253   const Register kRegisters[] = {r0, r1, r2,  r3, r4, r5,  r6,  r7,
254                                  r8, r9, r10, fp, ip, r13, r14, sp};
255   return kRegisters[num];
256 }
257 
258 // -----------------------------------------------------------------------------
259 // Implementation of RelocInfo
260 
261 const int RelocInfo::kApplyMask =
262     RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
263     RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
264 
IsCodedSpecially()265 bool RelocInfo::IsCodedSpecially() {
266   // The deserializer needs to know whether a pointer is specially
267   // coded.  Being specially coded on S390 means that it is an iihf/iilf
268   // instruction sequence, and that is always the case inside code
269   // objects.
270   return true;
271 }
272 
IsInConstantPool()273 bool RelocInfo::IsInConstantPool() { return false; }
274 
GetDeoptimizationId(Isolate * isolate,DeoptimizeKind kind)275 int RelocInfo::GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind) {
276   DCHECK(IsRuntimeEntry(rmode_));
277   return Deoptimizer::GetDeoptimizationId(isolate, target_address(), kind);
278 }
279 
set_js_to_wasm_address(Address address,ICacheFlushMode icache_flush_mode)280 void RelocInfo::set_js_to_wasm_address(Address address,
281                                        ICacheFlushMode icache_flush_mode) {
282   DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
283   Assembler::set_target_address_at(pc_, constant_pool_, address,
284                                    icache_flush_mode);
285 }
286 
js_to_wasm_address() const287 Address RelocInfo::js_to_wasm_address() const {
288   DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
289   return Assembler::target_address_at(pc_, constant_pool_);
290 }
291 
wasm_call_tag() const292 uint32_t RelocInfo::wasm_call_tag() const {
293   DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
294   return static_cast<uint32_t>(
295       Assembler::target_address_at(pc_, constant_pool_));
296 }
297 
298 // -----------------------------------------------------------------------------
299 // Implementation of Operand and MemOperand
300 // See assembler-s390-inl.h for inlined constructors
301 
Operand(Handle<HeapObject> handle)302 Operand::Operand(Handle<HeapObject> handle) {
303   AllowHandleDereference using_location;
304   rm_ = no_reg;
305   value_.immediate = static_cast<intptr_t>(handle.address());
306   rmode_ = RelocInfo::EMBEDDED_OBJECT;
307 }
308 
EmbeddedNumber(double value)309 Operand Operand::EmbeddedNumber(double value) {
310   int32_t smi;
311   if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi));
312   Operand result(0, RelocInfo::EMBEDDED_OBJECT);
313   result.is_heap_object_request_ = true;
314   result.value_.heap_object_request = HeapObjectRequest(value);
315   return result;
316 }
317 
MemOperand(Register rn,int32_t offset)318 MemOperand::MemOperand(Register rn, int32_t offset)
319     : baseRegister(rn), indexRegister(r0), offset_(offset) {}
320 
MemOperand(Register rx,Register rb,int32_t offset)321 MemOperand::MemOperand(Register rx, Register rb, int32_t offset)
322     : baseRegister(rb), indexRegister(rx), offset_(offset) {}
323 
AllocateAndInstallRequestedHeapObjects(Isolate * isolate)324 void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
325   for (auto& request : heap_object_requests_) {
326     Handle<HeapObject> object;
327     Address pc = reinterpret_cast<Address>(buffer_ + request.offset());
328     switch (request.kind()) {
329       case HeapObjectRequest::kHeapNumber:
330         object =
331             isolate->factory()->NewHeapNumber(request.heap_number(), TENURED);
332         set_target_address_at(pc, kNullAddress,
333                               reinterpret_cast<Address>(object.location()),
334                               SKIP_ICACHE_FLUSH);
335         break;
336       case HeapObjectRequest::kCodeStub:
337         request.code_stub()->set_isolate(isolate);
338         SixByteInstr instr =
339             Instruction::InstructionBits(reinterpret_cast<const byte*>(pc));
340         int index = instr & 0xFFFFFFFF;
341         UpdateCodeTarget(index, request.code_stub()->GetCode());
342         break;
343     }
344   }
345 }
346 
347 // -----------------------------------------------------------------------------
348 // Specific instructions, constants, and masks.
349 
Assembler(const AssemblerOptions & options,void * buffer,int buffer_size)350 Assembler::Assembler(const AssemblerOptions& options, void* buffer,
351                      int buffer_size)
352     : AssemblerBase(options, buffer, buffer_size) {
353   reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
354   ReserveCodeTargetSpace(100);
355   last_bound_pos_ = 0;
356   relocations_.reserve(128);
357 }
358 
GetCode(Isolate * isolate,CodeDesc * desc)359 void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
360   EmitRelocations();
361 
362   AllocateAndInstallRequestedHeapObjects(isolate);
363 
364   // Set up code descriptor.
365   desc->buffer = buffer_;
366   desc->buffer_size = buffer_size_;
367   desc->instr_size = pc_offset();
368   desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
369   desc->constant_pool_size = 0;
370   desc->origin = this;
371   desc->unwinding_info_size = 0;
372   desc->unwinding_info = nullptr;
373 }
374 
Align(int m)375 void Assembler::Align(int m) {
376   DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
377   while ((pc_offset() & (m - 1)) != 0) {
378     nop(0);
379   }
380 }
381 
CodeTargetAlign()382 void Assembler::CodeTargetAlign() { Align(8); }
383 
GetCondition(Instr instr)384 Condition Assembler::GetCondition(Instr instr) {
385   switch (instr & kCondMask) {
386     case BT:
387       return eq;
388     case BF:
389       return ne;
390     default:
391       UNIMPLEMENTED();
392   }
393   return al;
394 }
395 
396 #if V8_TARGET_ARCH_S390X
397 // This code assumes a FIXED_SEQUENCE for 64bit loads (iihf/iilf)
Is64BitLoadIntoIP(SixByteInstr instr1,SixByteInstr instr2)398 bool Assembler::Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2) {
399   // Check the instructions are the iihf/iilf load into ip
400   return (((instr1 >> 32) == 0xC0C8) && ((instr2 >> 32) == 0xC0C9));
401 }
402 #else
403 // This code assumes a FIXED_SEQUENCE for 32bit loads (iilf)
Is32BitLoadIntoIP(SixByteInstr instr)404 bool Assembler::Is32BitLoadIntoIP(SixByteInstr instr) {
405   // Check the instruction is an iilf load into ip/r12.
406   return ((instr >> 32) == 0xC0C9);
407 }
408 #endif
409 
410 // Labels refer to positions in the (to be) generated code.
411 // There are bound, linked, and unused labels.
412 //
413 // Bound labels refer to known positions in the already
414 // generated code. pos() is the position the label refers to.
415 //
416 // Linked labels refer to unknown positions in the code
417 // to be generated; pos() is the position of the last
418 // instruction using the label.
419 
420 // The link chain is terminated by a negative code position (must be aligned)
421 const int kEndOfChain = -4;
422 
423 // Returns the target address of the relative instructions, typically
424 // of the form: pos + imm (where immediate is in # of halfwords for
425 // BR* and LARL).
target_at(int pos)426 int Assembler::target_at(int pos) {
427   SixByteInstr instr = instr_at(pos);
428   // check which type of branch this is 16 or 26 bit offset
429   Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
430 
431   if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
432     int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
433     imm16 <<= 1;  // immediate is in # of halfwords
434     if (imm16 == 0) return kEndOfChain;
435     return pos + imm16;
436   } else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
437              BRASL == opcode) {
438     int32_t imm32 =
439         static_cast<int32_t>(instr & (static_cast<uint64_t>(0xFFFFFFFF)));
440     if (LLILF != opcode)
441       imm32 <<= 1;  // BR* + LARL treat immediate in # of halfwords
442     if (imm32 == 0) return kEndOfChain;
443     return pos + imm32;
444   } else if (BRXHG == opcode) {
445     // offset is in bits 16-31 of 48 bit instruction
446     instr = instr >> 16;
447     int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
448     imm16 <<= 1;  // immediate is in # of halfwords
449     if (imm16 == 0) return kEndOfChain;
450     return pos + imm16;
451   }
452 
453   // Unknown condition
454   DCHECK(false);
455   return -1;
456 }
457 
458 // Update the target address of the current relative instruction.
target_at_put(int pos,int target_pos,bool * is_branch)459 void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
460   SixByteInstr instr = instr_at(pos);
461   Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
462 
463   if (is_branch != nullptr) {
464     *is_branch = (opcode == BRC || opcode == BRCT || opcode == BRCTG ||
465                   opcode == BRCL || opcode == BRASL || opcode == BRXH ||
466                   opcode == BRXHG);
467   }
468 
469   if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
470     int16_t imm16 = target_pos - pos;
471     instr &= (~0xFFFF);
472     DCHECK(is_int16(imm16));
473     instr_at_put<FourByteInstr>(pos, instr | (imm16 >> 1));
474     return;
475   } else if (BRCL == opcode || LARL == opcode || BRASL == opcode) {
476     // Immediate is in # of halfwords
477     int32_t imm32 = target_pos - pos;
478     instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
479     instr_at_put<SixByteInstr>(pos, instr | (imm32 >> 1));
480     return;
481   } else if (LLILF == opcode) {
482     DCHECK(target_pos == kEndOfChain || target_pos >= 0);
483     // Emitted label constant, not part of a branch.
484     // Make label relative to Code* of generated Code object.
485     int32_t imm32 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
486     instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
487     instr_at_put<SixByteInstr>(pos, instr | imm32);
488     return;
489   } else if (BRXHG == opcode) {
490     // Immediate is in bits 16-31 of 48 bit instruction
491     int32_t imm16 = target_pos - pos;
492     instr &= (0xFFFF0000FFFF); // clear bits 16-31
493     imm16 &= 0xFFFF;           // clear high halfword
494     imm16 <<= 16;
495     // Immediate is in # of halfwords
496     instr_at_put<SixByteInstr>(pos, instr | (imm16 >> 1));
497     return;
498   }
499   DCHECK(false);
500 }
501 
502 // Returns the maximum number of bits given instruction can address.
max_reach_from(int pos)503 int Assembler::max_reach_from(int pos) {
504   Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
505   // Check which type of instr.  In theory, we can return
506   // the values below + 1, given offset is # of halfwords
507   if (BRC == opcode || BRCT == opcode || BRCTG == opcode|| BRXH == opcode ||
508       BRXHG == opcode) {
509     return 16;
510   } else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
511              BRASL == opcode) {
512     return 31;  // Using 31 as workaround instead of 32 as
513                 // is_intn(x,32) doesn't work on 32-bit platforms.
514                 // llilf: Emitted label constant, not part of
515                 //        a branch (regexp PushBacktrack).
516   }
517   DCHECK(false);
518   return 16;
519 }
520 
bind_to(Label * L,int pos)521 void Assembler::bind_to(Label* L, int pos) {
522   DCHECK(0 <= pos && pos <= pc_offset());  // must have a valid binding position
523   bool is_branch = false;
524   while (L->is_linked()) {
525     int fixup_pos = L->pos();
526 #ifdef DEBUG
527     int32_t offset = pos - fixup_pos;
528     int maxReach = max_reach_from(fixup_pos);
529 #endif
530     next(L);  // call next before overwriting link with target at fixup_pos
531     DCHECK(is_intn(offset, maxReach));
532     target_at_put(fixup_pos, pos, &is_branch);
533   }
534   L->bind_to(pos);
535 
536   // Keep track of the last bound label so we don't eliminate any instructions
537   // before a bound label.
538   if (pos > last_bound_pos_) last_bound_pos_ = pos;
539 }
540 
bind(Label * L)541 void Assembler::bind(Label* L) {
542   DCHECK(!L->is_bound());  // label can only be bound once
543   bind_to(L, pc_offset());
544 }
545 
next(Label * L)546 void Assembler::next(Label* L) {
547   DCHECK(L->is_linked());
548   int link = target_at(L->pos());
549   if (link == kEndOfChain) {
550     L->Unuse();
551   } else {
552     DCHECK_GE(link, 0);
553     L->link_to(link);
554   }
555 }
556 
is_near(Label * L,Condition cond)557 bool Assembler::is_near(Label* L, Condition cond) {
558   DCHECK(L->is_bound());
559   if (L->is_bound() == false) return false;
560 
561   int maxReach = ((cond == al) ? 26 : 16);
562   int offset = L->pos() - pc_offset();
563 
564   return is_intn(offset, maxReach);
565 }
566 
link(Label * L)567 int Assembler::link(Label* L) {
568   int position;
569   if (L->is_bound()) {
570     position = L->pos();
571   } else {
572     if (L->is_linked()) {
573       position = L->pos();  // L's link
574     } else {
575       // was: target_pos = kEndOfChain;
576       // However, using self to mark the first reference
577       // should avoid most instances of branch offset overflow.  See
578       // target_at() for where this is converted back to kEndOfChain.
579       position = pc_offset();
580     }
581     L->link_to(pc_offset());
582   }
583 
584   return position;
585 }
586 
load_label_offset(Register r1,Label * L)587 void Assembler::load_label_offset(Register r1, Label* L) {
588   int target_pos;
589   int constant;
590   if (L->is_bound()) {
591     target_pos = L->pos();
592     constant = target_pos + (Code::kHeaderSize - kHeapObjectTag);
593   } else {
594     if (L->is_linked()) {
595       target_pos = L->pos();  // L's link
596     } else {
597       // was: target_pos = kEndOfChain;
598       // However, using branch to self to mark the first reference
599       // should avoid most instances of branch offset overflow.  See
600       // target_at() for where this is converted back to kEndOfChain.
601       target_pos = pc_offset();
602     }
603     L->link_to(pc_offset());
604 
605     constant = target_pos - pc_offset();
606   }
607   llilf(r1, Operand(constant));
608 }
609 
610 // Pseudo op - branch on condition
branchOnCond(Condition c,int branch_offset,bool is_bound)611 void Assembler::branchOnCond(Condition c, int branch_offset, bool is_bound) {
612   int offset_in_halfwords = branch_offset / 2;
613   if (is_bound && is_int16(offset_in_halfwords)) {
614     brc(c, Operand(offset_in_halfwords));  // short jump
615   } else {
616     brcl(c, Operand(offset_in_halfwords));  // long jump
617   }
618 }
619 
620 // Exception-generating instructions and debugging support.
621 // Stops with a non-negative code less than kNumOfWatchedStops support
622 // enabling/disabling and a counter feature. See simulator-s390.h .
stop(const char * msg,Condition cond,int32_t code,CRegister cr)623 void Assembler::stop(const char* msg, Condition cond, int32_t code,
624                      CRegister cr) {
625   if (cond != al) {
626     Label skip;
627     b(NegateCondition(cond), &skip, Label::kNear);
628     bkpt(0);
629     bind(&skip);
630   } else {
631     bkpt(0);
632   }
633 }
634 
bkpt(uint32_t imm16)635 void Assembler::bkpt(uint32_t imm16) {
636   // GDB software breakpoint instruction
637   emit2bytes(0x0001);
638 }
639 
640 // Pseudo instructions.
nop(int type)641 void Assembler::nop(int type) {
642   switch (type) {
643     case 0:
644       lr(r0, r0);
645       break;
646     case DEBUG_BREAK_NOP:
647       // TODO(john.yan): Use a better NOP break
648       oill(r3, Operand::Zero());
649       break;
650     default:
651       UNIMPLEMENTED();
652   }
653 }
654 
655 // -------------------------
656 // Load Address Instructions
657 // -------------------------
658 // Load Address Relative Long
larl(Register r1,Label * l)659 void Assembler::larl(Register r1, Label* l) {
660   larl(r1, Operand(branch_offset(l)));
661 }
662 
EnsureSpaceFor(int space_needed)663 void Assembler::EnsureSpaceFor(int space_needed) {
664   if (buffer_space() <= (kGap + space_needed)) {
665     GrowBuffer(space_needed);
666   }
667 }
668 
call(Handle<Code> target,RelocInfo::Mode rmode)669 void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
670   DCHECK(RelocInfo::IsCodeTarget(rmode));
671   EnsureSpace ensure_space(this);
672 
673   RecordRelocInfo(rmode);
674   int32_t target_index = AddCodeTarget(target);
675   brasl(r14, Operand(target_index));
676 }
677 
call(CodeStub * stub)678 void Assembler::call(CodeStub* stub) {
679   EnsureSpace ensure_space(this);
680   RequestHeapObject(HeapObjectRequest(stub));
681   RecordRelocInfo(RelocInfo::CODE_TARGET);
682   int32_t target_index = AddCodeTarget(Handle<Code>());
683   brasl(r14, Operand(target_index));
684 }
685 
jump(Handle<Code> target,RelocInfo::Mode rmode,Condition cond)686 void Assembler::jump(Handle<Code> target, RelocInfo::Mode rmode,
687                      Condition cond) {
688   DCHECK(RelocInfo::IsCodeTarget(rmode));
689   EnsureSpace ensure_space(this);
690 
691   RecordRelocInfo(rmode);
692   int32_t target_index = AddCodeTarget(target);
693   brcl(cond, Operand(target_index));
694 }
695 
696 // end of S390instructions
697 
IsNop(SixByteInstr instr,int type)698 bool Assembler::IsNop(SixByteInstr instr, int type) {
699   DCHECK((0 == type) || (DEBUG_BREAK_NOP == type));
700   if (DEBUG_BREAK_NOP == type) {
701     return ((instr & 0xFFFFFFFF) == 0xA53B0000);  // oill r3, 0
702   }
703   return ((instr & 0xFFFF) == 0x1800);  // lr r0,r0
704 }
705 
706 // dummy instruction reserved for special use.
dumy(int r1,int x2,int b2,int d2)707 void Assembler::dumy(int r1, int x2, int b2, int d2) {
708 #if defined(USE_SIMULATOR)
709   int op = 0xE353;
710   uint64_t code = (static_cast<uint64_t>(op & 0xFF00)) * B32 |
711                   (static_cast<uint64_t>(r1) & 0xF) * B36 |
712                   (static_cast<uint64_t>(x2) & 0xF) * B32 |
713                   (static_cast<uint64_t>(b2) & 0xF) * B28 |
714                   (static_cast<uint64_t>(d2 & 0x0FFF)) * B16 |
715                   (static_cast<uint64_t>(d2 & 0x0FF000)) >> 4 |
716                   (static_cast<uint64_t>(op & 0x00FF));
717   emit6bytes(code);
718 #endif
719 }
720 
GrowBuffer(int needed)721 void Assembler::GrowBuffer(int needed) {
722   if (!own_buffer_) FATAL("external code buffer is too small");
723 
724   // Compute new buffer size.
725   CodeDesc desc;  // the new buffer
726   if (buffer_size_ < 4 * KB) {
727     desc.buffer_size = 4 * KB;
728   } else if (buffer_size_ < 1 * MB) {
729     desc.buffer_size = 2 * buffer_size_;
730   } else {
731     desc.buffer_size = buffer_size_ + 1 * MB;
732   }
733   int space = buffer_space() + (desc.buffer_size - buffer_size_);
734   if (space < needed) {
735     desc.buffer_size += needed - space;
736   }
737 
738   // Some internal data structures overflow for very large buffers,
739   // they must ensure that kMaximalBufferSize is not too large.
740   if (desc.buffer_size > kMaximalBufferSize) {
741     V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
742   }
743 
744   // Set up new buffer.
745   desc.buffer = NewArray<byte>(desc.buffer_size);
746   desc.origin = this;
747 
748   desc.instr_size = pc_offset();
749   desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
750 
751   // Copy the data.
752   intptr_t pc_delta = desc.buffer - buffer_;
753   intptr_t rc_delta =
754       (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
755   memmove(desc.buffer, buffer_, desc.instr_size);
756   memmove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
757           desc.reloc_size);
758 
759   // Switch buffers.
760   DeleteArray(buffer_);
761   buffer_ = desc.buffer;
762   buffer_size_ = desc.buffer_size;
763   pc_ += pc_delta;
764   reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
765                                reloc_info_writer.last_pc() + pc_delta);
766 
767   // None of our relocation types are pc relative pointing outside the code
768   // buffer nor pc absolute pointing inside the code buffer, so there is no need
769   // to relocate any emitted relocation entries.
770 }
771 
db(uint8_t data)772 void Assembler::db(uint8_t data) {
773   CheckBuffer();
774   *reinterpret_cast<uint8_t*>(pc_) = data;
775   pc_ += sizeof(uint8_t);
776 }
777 
dd(uint32_t data)778 void Assembler::dd(uint32_t data) {
779   CheckBuffer();
780   *reinterpret_cast<uint32_t*>(pc_) = data;
781   pc_ += sizeof(uint32_t);
782 }
783 
dq(uint64_t value)784 void Assembler::dq(uint64_t value) {
785   CheckBuffer();
786   *reinterpret_cast<uint64_t*>(pc_) = value;
787   pc_ += sizeof(uint64_t);
788 }
789 
dp(uintptr_t data)790 void Assembler::dp(uintptr_t data) {
791   CheckBuffer();
792   *reinterpret_cast<uintptr_t*>(pc_) = data;
793   pc_ += sizeof(uintptr_t);
794 }
795 
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)796 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
797   if (options().disable_reloc_info_for_patching) return;
798   if (RelocInfo::IsNone(rmode) ||
799       // Don't record external references unless the heap will be serialized.
800       (RelocInfo::IsOnlyForSerializer(rmode) &&
801        !options().record_reloc_info_for_serialization && !emit_debug_code())) {
802     return;
803   }
804   DeferredRelocInfo rinfo(pc_offset(), rmode, data);
805   relocations_.push_back(rinfo);
806 }
807 
emit_label_addr(Label * label)808 void Assembler::emit_label_addr(Label* label) {
809   CheckBuffer();
810   RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
811   int position = link(label);
812   DCHECK(label->is_bound());
813   // Keep internal references relative until EmitRelocations.
814   dp(position);
815 }
816 
EmitRelocations()817 void Assembler::EmitRelocations() {
818   EnsureSpaceFor(relocations_.size() * kMaxRelocSize);
819 
820   for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
821        it != relocations_.end(); it++) {
822     RelocInfo::Mode rmode = it->rmode();
823     Address pc = reinterpret_cast<Address>(buffer_) + it->position();
824     RelocInfo rinfo(pc, rmode, it->data(), nullptr);
825 
826     // Fix up internal references now that they are guaranteed to be bound.
827     if (RelocInfo::IsInternalReference(rmode)) {
828       // Jump table entry
829       Address pos = Memory<Address>(pc);
830       Memory<Address>(pc) = reinterpret_cast<Address>(buffer_) + pos;
831     } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
832       // mov sequence
833       Address pos = target_address_at(pc, 0);
834       set_target_address_at(pc, 0, reinterpret_cast<Address>(buffer_) + pos,
835                             SKIP_ICACHE_FLUSH);
836     }
837 
838     reloc_info_writer.Write(&rinfo);
839   }
840 }
841 
842 }  // namespace internal
843 }  // namespace v8
844 #endif  // V8_TARGET_ARCH_S390
845