blob: ae3dd5820944ced1a8cd8b56e89e0091f467ceb3 [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Declares a Simulator for S390 instructions if we are not generating a native
6// S390 binary. This Simulator allows us to run and debug S390 code generation
7// on regular desktop machines.
8// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
9// which will start execution in the Simulator or forwards to the real entry
10// on a S390 hardware platform.
11
12#ifndef V8_S390_SIMULATOR_S390_H_
13#define V8_S390_SIMULATOR_S390_H_
14
15#include "src/allocation.h"
16
17#if !defined(USE_SIMULATOR)
18// Running without a simulator on a native s390 platform.
19
20namespace v8 {
21namespace internal {
22
23// When running without a simulator we call the entry directly.
24#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
25 (entry(p0, p1, p2, p3, p4))
26
27typedef int (*s390_regexp_matcher)(String*, int, const byte*, const byte*, int*,
28 int, Address, int, void*, Isolate*);
29
30// Call the generated regexp code directly. The code at the entry address
31// should act as a function matching the type ppc_regexp_matcher.
32// The ninth argument is a dummy that reserves the space used for
33// the return address added by the ExitFrame in native calls.
34#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
35 p7, p8) \
36 (FUNCTION_CAST<s390_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, \
37 NULL, p8))
38
39// The stack limit beyond which we will throw stack overflow errors in
40// generated code. Because generated code on s390 uses the C stack, we
41// just use the C stack limit.
42class SimulatorStack : public v8::internal::AllStatic {
43 public:
44 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
45 uintptr_t c_limit) {
46 USE(isolate);
47 return c_limit;
48 }
49
50 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
51 uintptr_t try_catch_address) {
52 USE(isolate);
53 return try_catch_address;
54 }
55
56 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
57 USE(isolate);
58 }
59};
60} // namespace internal
61} // namespace v8
62
63#else // !defined(USE_SIMULATOR)
64// Running with a simulator.
65
66#include "src/assembler.h"
67#include "src/hashmap.h"
68#include "src/s390/constants-s390.h"
69
70namespace v8 {
71namespace internal {
72
73class CachePage {
74 public:
75 static const int LINE_VALID = 0;
76 static const int LINE_INVALID = 1;
77
78 static const int kPageShift = 12;
79 static const int kPageSize = 1 << kPageShift;
80 static const int kPageMask = kPageSize - 1;
81 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
82 static const int kLineLength = 1 << kLineShift;
83 static const int kLineMask = kLineLength - 1;
84
85 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
86
87 char* ValidityByte(int offset) {
88 return &validity_map_[offset >> kLineShift];
89 }
90
91 char* CachedData(int offset) { return &data_[offset]; }
92
93 private:
94 char data_[kPageSize]; // The cached data.
95 static const int kValidityMapSize = kPageSize >> kLineShift;
96 char validity_map_[kValidityMapSize]; // One byte per line.
97};
98
99class Simulator {
100 public:
101 friend class S390Debugger;
102 enum Register {
103 no_reg = -1,
104 r0 = 0,
105 r1 = 1,
106 r2 = 2,
107 r3 = 3,
108 r4 = 4,
109 r5 = 5,
110 r6 = 6,
111 r7 = 7,
112 r8 = 8,
113 r9 = 9,
114 r10 = 10,
115 r11 = 11,
116 r12 = 12,
117 r13 = 13,
118 r14 = 14,
119 r15 = 15,
120 fp = r11,
121 ip = r12,
122 cp = r13,
123 ra = r14,
124 sp = r15, // name aliases
125 kNumGPRs = 16,
126 d0 = 0,
127 d1,
128 d2,
129 d3,
130 d4,
131 d5,
132 d6,
133 d7,
134 d8,
135 d9,
136 d10,
137 d11,
138 d12,
139 d13,
140 d14,
141 d15,
142 kNumFPRs = 16
143 };
144
145 explicit Simulator(Isolate* isolate);
146 ~Simulator();
147
148 // The currently executing Simulator instance. Potentially there can be one
149 // for each native thread.
150 static Simulator* current(v8::internal::Isolate* isolate);
151
152 // Accessors for register state.
153 void set_register(int reg, uint64_t value);
154 uint64_t get_register(int reg) const;
155 template <typename T>
156 T get_low_register(int reg) const;
157 template <typename T>
158 T get_high_register(int reg) const;
159 void set_low_register(int reg, uint32_t value);
160 void set_high_register(int reg, uint32_t value);
161
162 double get_double_from_register_pair(int reg);
163 void set_d_register_from_double(int dreg, const double dbl) {
164 DCHECK(dreg >= 0 && dreg < kNumFPRs);
165 *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
166 }
167
168 double get_double_from_d_register(int dreg) {
169 DCHECK(dreg >= 0 && dreg < kNumFPRs);
170 return *bit_cast<double*>(&fp_registers_[dreg]);
171 }
172 void set_d_register(int dreg, int64_t value) {
173 DCHECK(dreg >= 0 && dreg < kNumFPRs);
174 fp_registers_[dreg] = value;
175 }
176 int64_t get_d_register(int dreg) {
177 DCHECK(dreg >= 0 && dreg < kNumFPRs);
178 return fp_registers_[dreg];
179 }
180
181 void set_d_register_from_float32(int dreg, const float f) {
182 DCHECK(dreg >= 0 && dreg < kNumFPRs);
183
184 int32_t f_int = *bit_cast<int32_t*>(&f);
185 int64_t finalval = static_cast<int64_t>(f_int) << 32;
186 set_d_register(dreg, finalval);
187 }
188
189 float get_float32_from_d_register(int dreg) {
190 DCHECK(dreg >= 0 && dreg < kNumFPRs);
191
192 int64_t regval = get_d_register(dreg) >> 32;
193 int32_t regval32 = static_cast<int32_t>(regval);
194 return *bit_cast<float*>(&regval32);
195 }
196
197 // Special case of set_register and get_register to access the raw PC value.
198 void set_pc(intptr_t value);
199 intptr_t get_pc() const;
200
201 Address get_sp() const {
202 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
203 }
204
205 // Accessor to the internal simulator stack area.
206 uintptr_t StackLimit(uintptr_t c_limit) const;
207
208 // Executes S390 instructions until the PC reaches end_sim_pc.
209 void Execute();
210
211 // Call on program start.
212 static void Initialize(Isolate* isolate);
213
214 static void TearDown(HashMap* i_cache, Redirection* first);
215
216 // V8 generally calls into generated JS code with 5 parameters and into
217 // generated RegExp code with 7 parameters. This is a convenience function,
218 // which sets up the simulator state and grabs the result on return.
219 intptr_t Call(byte* entry, int argument_count, ...);
220 // Alternative: call a 2-argument double function.
221 void CallFP(byte* entry, double d0, double d1);
222 int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
223 double CallFPReturnsDouble(byte* entry, double d0, double d1);
224
225 // Push an address onto the JS stack.
226 uintptr_t PushAddress(uintptr_t address);
227
228 // Pop an address from the JS stack.
229 uintptr_t PopAddress();
230
231 // Debugger input.
232 void set_last_debugger_input(char* input);
233 char* last_debugger_input() { return last_debugger_input_; }
234
235 // ICache checking.
236 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
237 size_t size);
238
239 // Returns true if pc register contains one of the 'special_values' defined
240 // below (bad_lr, end_sim_pc).
241 bool has_bad_pc() const;
242
243 private:
244 enum special_values {
245 // Known bad pc value to ensure that the simulator does not execute
246 // without being properly setup.
247 bad_lr = -1,
248 // A pc value used to signal the simulator to stop execution. Generally
249 // the lr is set to this value on transition from native C code to
250 // simulated execution, so that the simulator can "return" to the native
251 // C code.
252 end_sim_pc = -2
253 };
254
255 // Unsupported instructions use Format to print an error and stop execution.
256 void Format(Instruction* instr, const char* format);
257
258 // Helper functions to set the conditional flags in the architecture state.
259 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
260 bool BorrowFrom(int32_t left, int32_t right);
261 template <typename T1>
262 inline bool OverflowFromSigned(T1 alu_out, T1 left, T1 right, bool addition);
263
264 // Helper functions to decode common "addressing" modes
265 int32_t GetShiftRm(Instruction* instr, bool* carry_out);
266 int32_t GetImm(Instruction* instr, bool* carry_out);
267 void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
268 intptr_t* start_address, intptr_t* end_address);
269 void HandleRList(Instruction* instr, bool load);
270 void HandleVList(Instruction* inst);
271 void SoftwareInterrupt(Instruction* instr);
272
273 // Stop helper functions.
274 inline bool isStopInstruction(Instruction* instr);
275 inline bool isWatchedStop(uint32_t bkpt_code);
276 inline bool isEnabledStop(uint32_t bkpt_code);
277 inline void EnableStop(uint32_t bkpt_code);
278 inline void DisableStop(uint32_t bkpt_code);
279 inline void IncreaseStopCounter(uint32_t bkpt_code);
280 void PrintStopInfo(uint32_t code);
281
282 // Byte Reverse
283 inline int16_t ByteReverse(int16_t hword);
284 inline int32_t ByteReverse(int32_t word);
285
286 // Read and write memory.
287 inline uint8_t ReadBU(intptr_t addr);
288 inline int8_t ReadB(intptr_t addr);
289 inline void WriteB(intptr_t addr, uint8_t value);
290 inline void WriteB(intptr_t addr, int8_t value);
291
292 inline uint16_t ReadHU(intptr_t addr, Instruction* instr);
293 inline int16_t ReadH(intptr_t addr, Instruction* instr);
294 // Note: Overloaded on the sign of the value.
295 inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr);
296 inline void WriteH(intptr_t addr, int16_t value, Instruction* instr);
297
298 inline uint32_t ReadWU(intptr_t addr, Instruction* instr);
299 inline int32_t ReadW(intptr_t addr, Instruction* instr);
300 inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr);
301 inline void WriteW(intptr_t addr, int32_t value, Instruction* instr);
302
303 inline int64_t ReadDW(intptr_t addr);
304 inline double ReadDouble(intptr_t addr);
305 inline void WriteDW(intptr_t addr, int64_t value);
306
307 // S390
308 void Trace(Instruction* instr);
309 bool DecodeTwoByte(Instruction* instr);
310 bool DecodeFourByte(Instruction* instr);
311 bool DecodeFourByteArithmetic(Instruction* instr);
312 bool DecodeFourByteArithmetic64Bit(Instruction* instr);
313 bool DecodeFourByteFloatingPoint(Instruction* instr);
314 void DecodeFourByteFloatingPointIntConversion(Instruction* instr);
315 void DecodeFourByteFloatingPointRound(Instruction* instr);
316
317 bool DecodeSixByte(Instruction* instr);
318 bool DecodeSixByteArithmetic(Instruction* instr);
319 bool S390InstructionDecode(Instruction* instr);
320 void DecodeSixByteBitShift(Instruction* instr);
321
322 // Used by the CL**BR instructions.
323 template <typename T1, typename T2>
324 void SetS390RoundConditionCode(T1 r2_val, T2 max, T2 min) {
325 condition_reg_ = 0;
326 double r2_dval = static_cast<double>(r2_val);
327 double dbl_min = static_cast<double>(min);
328 double dbl_max = static_cast<double>(max);
329
330 if (r2_dval == 0.0)
331 condition_reg_ = 8;
332 else if (r2_dval < 0.0 && r2_dval >= dbl_min && std::isfinite(r2_dval))
333 condition_reg_ = 4;
334 else if (r2_dval > 0.0 && r2_dval <= dbl_max && std::isfinite(r2_dval))
335 condition_reg_ = 2;
336 else
337 condition_reg_ = 1;
338 }
339
340 template <typename T1>
341 void SetS390RoundConditionCode(T1 r2_val, int64_t max, int64_t min) {
342 condition_reg_ = 0;
343 double r2_dval = static_cast<double>(r2_val);
344 double dbl_min = static_cast<double>(min);
345 double dbl_max = static_cast<double>(max);
346
347 // Note that the IEEE 754 floating-point representations (both 32 and
348 // 64 bit) cannot exactly represent INT64_MAX. The closest it can get
349 // is INT64_max + 1. IEEE 754 FP can, though, represent INT64_MIN
350 // exactly.
351
352 // This is not an issue for INT32, as IEEE754 64-bit can represent
353 // INT32_MAX and INT32_MIN with exact precision.
354
355 if (r2_dval == 0.0)
356 condition_reg_ = 8;
357 else if (r2_dval < 0.0 && r2_dval >= dbl_min && std::isfinite(r2_dval))
358 condition_reg_ = 4;
359 else if (r2_dval > 0.0 && r2_dval < dbl_max && std::isfinite(r2_dval))
360 condition_reg_ = 2;
361 else
362 condition_reg_ = 1;
363 }
364
365 // Used by the CL**BR instructions.
366 template <typename T1, typename T2, typename T3>
367 void SetS390ConvertConditionCode(T1 src, T2 dst, T3 max) {
368 condition_reg_ = 0;
369 if (src == static_cast<T1>(0.0)) {
370 condition_reg_ |= 8;
371 } else if (src < static_cast<T1>(0.0) && static_cast<T2>(src) == 0 &&
372 std::isfinite(src)) {
373 condition_reg_ |= 4;
374 } else if (src > static_cast<T1>(0.0) && std::isfinite(src) &&
375 src < static_cast<T1>(max)) {
376 condition_reg_ |= 2;
377 } else {
378 condition_reg_ |= 1;
379 }
380 }
381
382 template <typename T>
383 void SetS390ConditionCode(T lhs, T rhs) {
384 condition_reg_ = 0;
385 if (lhs == rhs) {
386 condition_reg_ |= CC_EQ;
387 } else if (lhs < rhs) {
388 condition_reg_ |= CC_LT;
389 } else if (lhs > rhs) {
390 condition_reg_ |= CC_GT;
391 }
392
393 // We get down here only for floating point
394 // comparisons and the values are unordered
395 // i.e. NaN
396 if (condition_reg_ == 0) condition_reg_ = unordered;
397 }
398
399 // Used by arithmetic operations that use carry.
400 template <typename T>
401 void SetS390ConditionCodeCarry(T result, bool overflow) {
402 condition_reg_ = 0;
403 bool zero_result = (result == static_cast<T>(0));
404 if (zero_result && !overflow) {
405 condition_reg_ |= 8;
406 } else if (!zero_result && !overflow) {
407 condition_reg_ |= 4;
408 } else if (zero_result && overflow) {
409 condition_reg_ |= 2;
410 } else if (!zero_result && overflow) {
411 condition_reg_ |= 1;
412 }
413 if (condition_reg_ == 0) UNREACHABLE();
414 }
415
416 bool isNaN(double value) { return (value != value); }
417
418 // Set the condition code for bitwise operations
419 // CC0 is set if value == 0.
420 // CC1 is set if value != 0.
421 // CC2/CC3 are not set.
422 template <typename T>
423 void SetS390BitWiseConditionCode(T value) {
424 condition_reg_ = 0;
425
426 if (value == 0)
427 condition_reg_ |= CC_EQ;
428 else
429 condition_reg_ |= CC_LT;
430 }
431
432 void SetS390OverflowCode(bool isOF) {
433 if (isOF) condition_reg_ = CC_OF;
434 }
435
436 bool TestConditionCode(Condition mask) {
437 // Check for unconditional branch
438 if (mask == 0xf) return true;
439
440 return (condition_reg_ & mask) != 0;
441 }
442
443 // Executes one instruction.
444 void ExecuteInstruction(Instruction* instr, bool auto_incr_pc = true);
445
446 // ICache.
447 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
448 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
449 int size);
450 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
451
452 // Runtime call support.
453 static void* RedirectExternalReference(
454 Isolate* isolate, void* external_function,
455 v8::internal::ExternalReference::Type type);
456
457 // Handle arguments and return value for runtime FP functions.
458 void GetFpArgs(double* x, double* y, intptr_t* z);
459 void SetFpResult(const double& result);
460 void TrashCallerSaveRegisters();
461
462 void CallInternal(byte* entry, int reg_arg_count = 3);
463
464 // Architecture state.
465 // On z9 and higher and supported Linux on z Systems platforms, all registers
466 // are 64-bit, even in 31-bit mode.
467 uint64_t registers_[kNumGPRs];
468 int64_t fp_registers_[kNumFPRs];
469
470 // Condition Code register. In S390, the last 4 bits are used.
471 int32_t condition_reg_;
472 // Special register to track PC.
473 intptr_t special_reg_pc_;
474
475 // Simulator support.
476 char* stack_;
477 static const size_t stack_protection_size_ = 256 * kPointerSize;
478 bool pc_modified_;
479 int64_t icount_;
480
481 // Debugger input.
482 char* last_debugger_input_;
483
484 // Icache simulation
485 v8::internal::HashMap* i_cache_;
486
487 // Registered breakpoints.
488 Instruction* break_pc_;
489 Instr break_instr_;
490
491 v8::internal::Isolate* isolate_;
492
493 // A stop is watched if its code is less than kNumOfWatchedStops.
494 // Only watched stops support enabling/disabling and the counter feature.
495 static const uint32_t kNumOfWatchedStops = 256;
496
497 // Breakpoint is disabled if bit 31 is set.
498 static const uint32_t kStopDisabledBit = 1 << 31;
499
500 // A stop is enabled, meaning the simulator will stop when meeting the
501 // instruction, if bit 31 of watched_stops_[code].count is unset.
502 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
503 // the breakpoint was hit or gone through.
504 struct StopCountAndDesc {
505 uint32_t count;
506 char* desc;
507 };
508 StopCountAndDesc watched_stops_[kNumOfWatchedStops];
509 void DebugStart();
510};
511
512// When running with the simulator transition into simulated execution at this
513// point.
514#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
515 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \
516 FUNCTION_ADDR(entry), 5, (intptr_t)p0, (intptr_t)p1, (intptr_t)p2, \
517 (intptr_t)p3, (intptr_t)p4))
518
519#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
520 p7, p8) \
521 Simulator::current(isolate)->Call(entry, 10, (intptr_t)p0, (intptr_t)p1, \
522 (intptr_t)p2, (intptr_t)p3, (intptr_t)p4, \
523 (intptr_t)p5, (intptr_t)p6, (intptr_t)p7, \
524 (intptr_t)NULL, (intptr_t)p8)
525
526// The simulator has its own stack. Thus it has a different stack limit from
527// the C-based native code. The JS-based limit normally points near the end of
528// the simulator stack. When the C-based limit is exhausted we reflect that by
529// lowering the JS-based limit as well, to make stack checks trigger.
530class SimulatorStack : public v8::internal::AllStatic {
531 public:
532 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
533 uintptr_t c_limit) {
534 return Simulator::current(isolate)->StackLimit(c_limit);
535 }
536
537 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
538 uintptr_t try_catch_address) {
539 Simulator* sim = Simulator::current(isolate);
540 return sim->PushAddress(try_catch_address);
541 }
542
543 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
544 Simulator::current(isolate)->PopAddress();
545 }
546};
547
548} // namespace internal
549} // namespace v8
550
551#endif // !defined(USE_SIMULATOR)
552#endif // V8_S390_SIMULATOR_S390_H_