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