blob: d3163e8a50582ccaf42593983f1b13f97fac6c86 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
6// Declares a Simulator for PPC instructions if we are not generating a native
7// PPC binary. This Simulator allows us to run and debug PPC code generation on
8// regular desktop machines.
9// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
10// which will start execution in the Simulator or forwards to the real entry
11// on a PPC HW platform.
12
13#ifndef V8_PPC_SIMULATOR_PPC_H_
14#define V8_PPC_SIMULATOR_PPC_H_
15
16#include "src/allocation.h"
17
18#if !defined(USE_SIMULATOR)
19// Running without a simulator on a native ppc platform.
20
21namespace v8 {
22namespace internal {
23
24// When running without a simulator we call the entry directly.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
Emily Bernierd0a1eb72015-03-24 16:35:39 -040026 (entry(p0, p1, p2, p3, p4))
27
28typedef int (*ppc_regexp_matcher)(String*, int, const byte*, const byte*, int*,
29 int, Address, int, void*, Isolate*);
30
31
32// Call the generated regexp code directly. The code at the entry address
33// should act as a function matching the type ppc_regexp_matcher.
34// The ninth argument is a dummy that reserves the space used for
35// the return address added by the ExitFrame in native calls.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
37 p7, p8) \
38 (FUNCTION_CAST<ppc_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, \
Emily Bernierd0a1eb72015-03-24 16:35:39 -040039 NULL, p8))
40
41// The stack limit beyond which we will throw stack overflow errors in
42// generated code. Because generated code on ppc uses the C stack, we
43// just use the C stack limit.
44class SimulatorStack : public v8::internal::AllStatic {
45 public:
46 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
47 uintptr_t c_limit) {
48 USE(isolate);
49 return c_limit;
50 }
51
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
53 uintptr_t try_catch_address) {
54 USE(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055 return try_catch_address;
56 }
57
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
59 USE(isolate);
60 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040061};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062} // namespace internal
63} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064
65#else // !defined(USE_SIMULATOR)
66// Running with a simulator.
67
68#include "src/assembler.h"
Ben Murdoch61f157c2016-09-16 13:49:30 +010069#include "src/base/hashmap.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040070#include "src/ppc/constants-ppc.h"
71
72namespace v8 {
73namespace internal {
74
75class CachePage {
76 public:
77 static const int LINE_VALID = 0;
78 static const int LINE_INVALID = 1;
79
80 static const int kPageShift = 12;
81 static const int kPageSize = 1 << kPageShift;
82 static const int kPageMask = kPageSize - 1;
83 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
84 static const int kLineLength = 1 << kLineShift;
85 static const int kLineMask = kLineLength - 1;
86
87 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
88
89 char* ValidityByte(int offset) {
90 return &validity_map_[offset >> kLineShift];
91 }
92
93 char* CachedData(int offset) { return &data_[offset]; }
94
95 private:
96 char data_[kPageSize]; // The cached data.
97 static const int kValidityMapSize = kPageSize >> kLineShift;
98 char validity_map_[kValidityMapSize]; // One byte per line.
99};
100
101
102class Simulator {
103 public:
104 friend class PPCDebugger;
105 enum Register {
106 no_reg = -1,
107 r0 = 0,
108 sp,
109 r2,
110 r3,
111 r4,
112 r5,
113 r6,
114 r7,
115 r8,
116 r9,
117 r10,
118 r11,
119 r12,
120 r13,
121 r14,
122 r15,
123 r16,
124 r17,
125 r18,
126 r19,
127 r20,
128 r21,
129 r22,
130 r23,
131 r24,
132 r25,
133 r26,
134 r27,
135 r28,
136 r29,
137 r30,
138 fp,
139 kNumGPRs = 32,
140 d0 = 0,
141 d1,
142 d2,
143 d3,
144 d4,
145 d5,
146 d6,
147 d7,
148 d8,
149 d9,
150 d10,
151 d11,
152 d12,
153 d13,
154 d14,
155 d15,
156 d16,
157 d17,
158 d18,
159 d19,
160 d20,
161 d21,
162 d22,
163 d23,
164 d24,
165 d25,
166 d26,
167 d27,
168 d28,
169 d29,
170 d30,
171 d31,
172 kNumFPRs = 32
173 };
174
175 explicit Simulator(Isolate* isolate);
176 ~Simulator();
177
178 // The currently executing Simulator instance. Potentially there can be one
179 // for each native thread.
180 static Simulator* current(v8::internal::Isolate* isolate);
181
182 // Accessors for register state.
183 void set_register(int reg, intptr_t value);
184 intptr_t get_register(int reg) const;
185 double get_double_from_register_pair(int reg);
186 void set_d_register_from_double(int dreg, const double dbl) {
187 DCHECK(dreg >= 0 && dreg < kNumFPRs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 double get_double_from_d_register(int dreg) {
191 DCHECK(dreg >= 0 && dreg < kNumFPRs);
192 return *bit_cast<double*>(&fp_registers_[dreg]);
193 }
194 void set_d_register(int dreg, int64_t value) {
195 DCHECK(dreg >= 0 && dreg < kNumFPRs);
196 fp_registers_[dreg] = value;
197 }
198 int64_t get_d_register(int dreg) {
199 DCHECK(dreg >= 0 && dreg < kNumFPRs);
200 return fp_registers_[dreg];
201 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202
203 // Special case of set_register and get_register to access the raw PC value.
204 void set_pc(intptr_t value);
205 intptr_t get_pc() const;
206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 Address get_sp() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400208 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
209 }
210
211 // Accessor to the internal simulator stack area.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 uintptr_t StackLimit(uintptr_t c_limit) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213
214 // Executes PPC instructions until the PC reaches end_sim_pc.
215 void Execute();
216
217 // Call on program start.
218 static void Initialize(Isolate* isolate);
219
Ben Murdoch61f157c2016-09-16 13:49:30 +0100220 static void TearDown(base::HashMap* i_cache, Redirection* first);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 // V8 generally calls into generated JS code with 5 parameters and into
223 // generated RegExp code with 7 parameters. This is a convenience function,
224 // which sets up the simulator state and grabs the result on return.
225 intptr_t Call(byte* entry, int argument_count, ...);
226 // Alternative: call a 2-argument double function.
227 void CallFP(byte* entry, double d0, double d1);
228 int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
229 double CallFPReturnsDouble(byte* entry, double d0, double d1);
230
231 // Push an address onto the JS stack.
232 uintptr_t PushAddress(uintptr_t address);
233
234 // Pop an address from the JS stack.
235 uintptr_t PopAddress();
236
237 // Debugger input.
238 void set_last_debugger_input(char* input);
239 char* last_debugger_input() { return last_debugger_input_; }
240
241 // ICache checking.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100242 static void FlushICache(base::HashMap* i_cache, void* start, size_t size);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243
244 // Returns true if pc register contains one of the 'special_values' defined
245 // below (bad_lr, end_sim_pc).
246 bool has_bad_pc() const;
247
248 private:
249 enum special_values {
250 // Known bad pc value to ensure that the simulator does not execute
251 // without being properly setup.
252 bad_lr = -1,
253 // A pc value used to signal the simulator to stop execution. Generally
254 // the lr is set to this value on transition from native C code to
255 // simulated execution, so that the simulator can "return" to the native
256 // C code.
257 end_sim_pc = -2
258 };
259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG };
261
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 // Unsupported instructions use Format to print an error and stop execution.
263 void Format(Instruction* instr, const char* format);
264
265 // Helper functions to set the conditional flags in the architecture state.
266 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
267 bool BorrowFrom(int32_t left, int32_t right);
268 bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
269 bool addition);
270
271 // Helper functions to decode common "addressing" modes
272 int32_t GetShiftRm(Instruction* instr, bool* carry_out);
273 int32_t GetImm(Instruction* instr, bool* carry_out);
274 void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
275 intptr_t* start_address, intptr_t* end_address);
276 void HandleRList(Instruction* instr, bool load);
277 void HandleVList(Instruction* inst);
278 void SoftwareInterrupt(Instruction* instr);
279
280 // Stop helper functions.
281 inline bool isStopInstruction(Instruction* instr);
282 inline bool isWatchedStop(uint32_t bkpt_code);
283 inline bool isEnabledStop(uint32_t bkpt_code);
284 inline void EnableStop(uint32_t bkpt_code);
285 inline void DisableStop(uint32_t bkpt_code);
286 inline void IncreaseStopCounter(uint32_t bkpt_code);
287 void PrintStopInfo(uint32_t code);
288
289 // Read and write memory.
290 inline uint8_t ReadBU(intptr_t addr);
291 inline int8_t ReadB(intptr_t addr);
292 inline void WriteB(intptr_t addr, uint8_t value);
293 inline void WriteB(intptr_t addr, int8_t value);
294
295 inline uint16_t ReadHU(intptr_t addr, Instruction* instr);
296 inline int16_t ReadH(intptr_t addr, Instruction* instr);
297 // Note: Overloaded on the sign of the value.
298 inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr);
299 inline void WriteH(intptr_t addr, int16_t value, Instruction* instr);
300
301 inline uint32_t ReadWU(intptr_t addr, Instruction* instr);
302 inline int32_t ReadW(intptr_t addr, Instruction* instr);
303 inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr);
304 inline void WriteW(intptr_t addr, int32_t value, Instruction* instr);
305
306 intptr_t* ReadDW(intptr_t addr);
307 void WriteDW(intptr_t addr, int64_t value);
308
309 void Trace(Instruction* instr);
310 void SetCR0(intptr_t result, bool setSO = false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 void ExecuteBranchConditional(Instruction* instr, BCType type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 void ExecuteExt1(Instruction* instr);
313 bool ExecuteExt2_10bit(Instruction* instr);
314 bool ExecuteExt2_9bit_part1(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315 bool ExecuteExt2_9bit_part2(Instruction* instr);
316 void ExecuteExt2_5bit(Instruction* instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317 void ExecuteExt2(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 void ExecuteExt3(Instruction* instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 void ExecuteExt4(Instruction* instr);
320#if V8_TARGET_ARCH_PPC64
321 void ExecuteExt5(Instruction* instr);
322#endif
323 void ExecuteGeneric(Instruction* instr);
324
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
326 void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); }
327
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400328 // Executes one instruction.
329 void ExecuteInstruction(Instruction* instr);
330
331 // ICache.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100332 static void CheckICache(base::HashMap* i_cache, Instruction* instr);
333 static void FlushOnePage(base::HashMap* i_cache, intptr_t start, int size);
334 static CachePage* GetCachePage(base::HashMap* i_cache, void* page);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400335
336 // Runtime call support.
337 static void* RedirectExternalReference(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 Isolate* isolate, void* external_function,
339 v8::internal::ExternalReference::Type type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400340
341 // Handle arguments and return value for runtime FP functions.
342 void GetFpArgs(double* x, double* y, intptr_t* z);
343 void SetFpResult(const double& result);
344 void TrashCallerSaveRegisters();
345
346 void CallInternal(byte* entry);
347
348 // Architecture state.
349 // Saturating instructions require a Q flag to indicate saturation.
350 // There is currently no way to read the CPSR directly, and thus read the Q
351 // flag, so this is left unimplemented.
352 intptr_t registers_[kNumGPRs];
353 int32_t condition_reg_;
354 int32_t fp_condition_reg_;
355 intptr_t special_reg_lr_;
356 intptr_t special_reg_pc_;
357 intptr_t special_reg_ctr_;
358 int32_t special_reg_xer_;
359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 int64_t fp_registers_[kNumFPRs];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400361
362 // Simulator support.
363 char* stack_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 static const size_t stack_protection_size_ = 256 * kPointerSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400365 bool pc_modified_;
366 int icount_;
367
368 // Debugger input.
369 char* last_debugger_input_;
370
371 // Icache simulation
Ben Murdoch61f157c2016-09-16 13:49:30 +0100372 base::HashMap* i_cache_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373
374 // Registered breakpoints.
375 Instruction* break_pc_;
376 Instr break_instr_;
377
378 v8::internal::Isolate* isolate_;
379
380 // A stop is watched if its code is less than kNumOfWatchedStops.
381 // Only watched stops support enabling/disabling and the counter feature.
382 static const uint32_t kNumOfWatchedStops = 256;
383
384 // Breakpoint is disabled if bit 31 is set.
385 static const uint32_t kStopDisabledBit = 1 << 31;
386
387 // A stop is enabled, meaning the simulator will stop when meeting the
388 // instruction, if bit 31 of watched_stops_[code].count is unset.
389 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
390 // the breakpoint was hit or gone through.
391 struct StopCountAndDesc {
392 uint32_t count;
393 char* desc;
394 };
395 StopCountAndDesc watched_stops_[kNumOfWatchedStops];
396};
397
398
399// When running with the simulator transition into simulated execution at this
400// point.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
402 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \
403 FUNCTION_ADDR(entry), 5, (intptr_t)p0, (intptr_t)p1, (intptr_t)p2, \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400404 (intptr_t)p3, (intptr_t)p4))
405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
407 p7, p8) \
408 Simulator::current(isolate)->Call(entry, 10, (intptr_t)p0, (intptr_t)p1, \
409 (intptr_t)p2, (intptr_t)p3, (intptr_t)p4, \
410 (intptr_t)p5, (intptr_t)p6, (intptr_t)p7, \
411 (intptr_t)NULL, (intptr_t)p8)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412
413
414// The simulator has its own stack. Thus it has a different stack limit from
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415// the C-based native code. The JS-based limit normally points near the end of
416// the simulator stack. When the C-based limit is exhausted we reflect that by
417// lowering the JS-based limit as well, to make stack checks trigger.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400418class SimulatorStack : public v8::internal::AllStatic {
419 public:
420 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
421 uintptr_t c_limit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 return Simulator::current(isolate)->StackLimit(c_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400423 }
424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
426 uintptr_t try_catch_address) {
427 Simulator* sim = Simulator::current(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400428 return sim->PushAddress(try_catch_address);
429 }
430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
432 Simulator::current(isolate)->PopAddress();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400433 }
434};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435} // namespace internal
436} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437
438#endif // !defined(USE_SIMULATOR)
439#endif // V8_PPC_SIMULATOR_PPC_H_