| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_ARM64_SIMULATOR_ARM64_H_ | 5 #ifndef V8_ARM64_SIMULATOR_ARM64_H_ |
| 6 #define V8_ARM64_SIMULATOR_ARM64_H_ | 6 #define V8_ARM64_SIMULATOR_ARM64_H_ |
| 7 | 7 |
| 8 #include <stdarg.h> | 8 #include <stdarg.h> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 | 205 |
| 206 // A wrapper class that stores an argument for one of the above Call | 206 // A wrapper class that stores an argument for one of the above Call |
| 207 // functions. | 207 // functions. |
| 208 // | 208 // |
| 209 // Only arguments up to 64 bits in size are supported. | 209 // Only arguments up to 64 bits in size are supported. |
| 210 class CallArgument { | 210 class CallArgument { |
| 211 public: | 211 public: |
| 212 template<typename T> | 212 template<typename T> |
| 213 explicit CallArgument(T argument) { | 213 explicit CallArgument(T argument) { |
| 214 bits_ = 0; | 214 bits_ = 0; |
| 215 ASSERT(sizeof(argument) <= sizeof(bits_)); | 215 DCHECK(sizeof(argument) <= sizeof(bits_)); |
| 216 memcpy(&bits_, &argument, sizeof(argument)); | 216 memcpy(&bits_, &argument, sizeof(argument)); |
| 217 type_ = X_ARG; | 217 type_ = X_ARG; |
| 218 } | 218 } |
| 219 | 219 |
| 220 explicit CallArgument(double argument) { | 220 explicit CallArgument(double argument) { |
| 221 ASSERT(sizeof(argument) == sizeof(bits_)); | 221 DCHECK(sizeof(argument) == sizeof(bits_)); |
| 222 memcpy(&bits_, &argument, sizeof(argument)); | 222 memcpy(&bits_, &argument, sizeof(argument)); |
| 223 type_ = D_ARG; | 223 type_ = D_ARG; |
| 224 } | 224 } |
| 225 | 225 |
| 226 explicit CallArgument(float argument) { | 226 explicit CallArgument(float argument) { |
| 227 // TODO(all): CallArgument(float) is untested, remove this check once | 227 // TODO(all): CallArgument(float) is untested, remove this check once |
| 228 // tested. | 228 // tested. |
| 229 UNIMPLEMENTED(); | 229 UNIMPLEMENTED(); |
| 230 // Make the D register a NaN to try to trap errors if the callee expects a | 230 // Make the D register a NaN to try to trap errors if the callee expects a |
| 231 // double. If it expects a float, the callee should ignore the top word. | 231 // double. If it expects a float, the callee should ignore the top word. |
| 232 ASSERT(sizeof(kFP64SignallingNaN) == sizeof(bits_)); | 232 DCHECK(sizeof(kFP64SignallingNaN) == sizeof(bits_)); |
| 233 memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN)); | 233 memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN)); |
| 234 // Write the float payload to the S register. | 234 // Write the float payload to the S register. |
| 235 ASSERT(sizeof(argument) <= sizeof(bits_)); | 235 DCHECK(sizeof(argument) <= sizeof(bits_)); |
| 236 memcpy(&bits_, &argument, sizeof(argument)); | 236 memcpy(&bits_, &argument, sizeof(argument)); |
| 237 type_ = D_ARG; | 237 type_ = D_ARG; |
| 238 } | 238 } |
| 239 | 239 |
| 240 // This indicates the end of the arguments list, so that CallArgument | 240 // This indicates the end of the arguments list, so that CallArgument |
| 241 // objects can be passed into varargs functions. | 241 // objects can be passed into varargs functions. |
| 242 static CallArgument End() { return CallArgument(); } | 242 static CallArgument End() { return CallArgument(); } |
| 243 | 243 |
| 244 int64_t bits() const { return bits_; } | 244 int64_t bits() const { return bits_; } |
| 245 bool IsEnd() const { return type_ == NO_ARG; } | 245 bool IsEnd() const { return type_ == NO_ARG; } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 | 283 |
| 284 // Run the simulator. | 284 // Run the simulator. |
| 285 static const Instruction* kEndOfSimAddress; | 285 static const Instruction* kEndOfSimAddress; |
| 286 void DecodeInstruction(); | 286 void DecodeInstruction(); |
| 287 void Run(); | 287 void Run(); |
| 288 void RunFrom(Instruction* start); | 288 void RunFrom(Instruction* start); |
| 289 | 289 |
| 290 // Simulation helpers. | 290 // Simulation helpers. |
| 291 template <typename T> | 291 template <typename T> |
| 292 void set_pc(T new_pc) { | 292 void set_pc(T new_pc) { |
| 293 ASSERT(sizeof(T) == sizeof(pc_)); | 293 DCHECK(sizeof(T) == sizeof(pc_)); |
| 294 memcpy(&pc_, &new_pc, sizeof(T)); | 294 memcpy(&pc_, &new_pc, sizeof(T)); |
| 295 pc_modified_ = true; | 295 pc_modified_ = true; |
| 296 } | 296 } |
| 297 Instruction* pc() { return pc_; } | 297 Instruction* pc() { return pc_; } |
| 298 | 298 |
| 299 void increment_pc() { | 299 void increment_pc() { |
| 300 if (!pc_modified_) { | 300 if (!pc_modified_) { |
| 301 pc_ = pc_->following(); | 301 pc_ = pc_->following(); |
| 302 } | 302 } |
| 303 | 303 |
| 304 pc_modified_ = false; | 304 pc_modified_ = false; |
| 305 } | 305 } |
| 306 | 306 |
| 307 virtual void Decode(Instruction* instr) { | 307 virtual void Decode(Instruction* instr) { |
| 308 decoder_->Decode(instr); | 308 decoder_->Decode(instr); |
| 309 } | 309 } |
| 310 | 310 |
| 311 void ExecuteInstruction() { | 311 void ExecuteInstruction() { |
| 312 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize)); | 312 DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize)); |
| 313 CheckBreakNext(); | 313 CheckBreakNext(); |
| 314 Decode(pc_); | 314 Decode(pc_); |
| 315 LogProcessorState(); | 315 LogProcessorState(); |
| 316 increment_pc(); | 316 increment_pc(); |
| 317 CheckBreakpoints(); | 317 CheckBreakpoints(); |
| 318 } | 318 } |
| 319 | 319 |
| 320 // Declare all Visitor functions. | 320 // Declare all Visitor functions. |
| 321 #define DECLARE(A) void Visit##A(Instruction* instr); | 321 #define DECLARE(A) void Visit##A(Instruction* instr); |
| 322 VISITOR_LIST(DECLARE) | 322 VISITOR_LIST(DECLARE) |
| 323 #undef DECLARE | 323 #undef DECLARE |
| 324 | 324 |
| 325 bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const { | 325 bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const { |
| 326 return ((code == 31) && (r31mode == Reg31IsZeroRegister)); | 326 return ((code == 31) && (r31mode == Reg31IsZeroRegister)); |
| 327 } | 327 } |
| 328 | 328 |
| 329 // Register accessors. | 329 // Register accessors. |
| 330 // Return 'size' bits of the value of an integer register, as the specified | 330 // Return 'size' bits of the value of an integer register, as the specified |
| 331 // type. The value is zero-extended to fill the result. | 331 // type. The value is zero-extended to fill the result. |
| 332 // | 332 // |
| 333 template<typename T> | 333 template<typename T> |
| 334 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | 334 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { |
| 335 ASSERT(code < kNumberOfRegisters); | 335 DCHECK(code < kNumberOfRegisters); |
| 336 if (IsZeroRegister(code, r31mode)) { | 336 if (IsZeroRegister(code, r31mode)) { |
| 337 return 0; | 337 return 0; |
| 338 } | 338 } |
| 339 return registers_[code].Get<T>(); | 339 return registers_[code].Get<T>(); |
| 340 } | 340 } |
| 341 | 341 |
| 342 // Common specialized accessors for the reg() template. | 342 // Common specialized accessors for the reg() template. |
| 343 int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | 343 int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { |
| 344 return reg<int32_t>(code, r31mode); | 344 return reg<int32_t>(code, r31mode); |
| 345 } | 345 } |
| 346 | 346 |
| 347 int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | 347 int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { |
| 348 return reg<int64_t>(code, r31mode); | 348 return reg<int64_t>(code, r31mode); |
| 349 } | 349 } |
| 350 | 350 |
| 351 // Write 'size' bits of 'value' into an integer register. The value is | 351 // Write 'size' bits of 'value' into an integer register. The value is |
| 352 // zero-extended. This behaviour matches AArch64 register writes. | 352 // zero-extended. This behaviour matches AArch64 register writes. |
| 353 | 353 |
| 354 // Like set_reg(), but infer the access size from the template type. | 354 // Like set_reg(), but infer the access size from the template type. |
| 355 template<typename T> | 355 template<typename T> |
| 356 void set_reg(unsigned code, T value, | 356 void set_reg(unsigned code, T value, |
| 357 Reg31Mode r31mode = Reg31IsZeroRegister) { | 357 Reg31Mode r31mode = Reg31IsZeroRegister) { |
| 358 ASSERT(code < kNumberOfRegisters); | 358 DCHECK(code < kNumberOfRegisters); |
| 359 if (!IsZeroRegister(code, r31mode)) | 359 if (!IsZeroRegister(code, r31mode)) |
| 360 registers_[code].Set(value); | 360 registers_[code].Set(value); |
| 361 } | 361 } |
| 362 | 362 |
| 363 // Common specialized accessors for the set_reg() template. | 363 // Common specialized accessors for the set_reg() template. |
| 364 void set_wreg(unsigned code, int32_t value, | 364 void set_wreg(unsigned code, int32_t value, |
| 365 Reg31Mode r31mode = Reg31IsZeroRegister) { | 365 Reg31Mode r31mode = Reg31IsZeroRegister) { |
| 366 set_reg(code, value, r31mode); | 366 set_reg(code, value, r31mode); |
| 367 } | 367 } |
| 368 | 368 |
| 369 void set_xreg(unsigned code, int64_t value, | 369 void set_xreg(unsigned code, int64_t value, |
| 370 Reg31Mode r31mode = Reg31IsZeroRegister) { | 370 Reg31Mode r31mode = Reg31IsZeroRegister) { |
| 371 set_reg(code, value, r31mode); | 371 set_reg(code, value, r31mode); |
| 372 } | 372 } |
| 373 | 373 |
| 374 // Commonly-used special cases. | 374 // Commonly-used special cases. |
| 375 template<typename T> | 375 template<typename T> |
| 376 void set_lr(T value) { | 376 void set_lr(T value) { |
| 377 ASSERT(sizeof(T) == kPointerSize); | 377 DCHECK(sizeof(T) == kPointerSize); |
| 378 set_reg(kLinkRegCode, value); | 378 set_reg(kLinkRegCode, value); |
| 379 } | 379 } |
| 380 | 380 |
| 381 template<typename T> | 381 template<typename T> |
| 382 void set_sp(T value) { | 382 void set_sp(T value) { |
| 383 ASSERT(sizeof(T) == kPointerSize); | 383 DCHECK(sizeof(T) == kPointerSize); |
| 384 set_reg(31, value, Reg31IsStackPointer); | 384 set_reg(31, value, Reg31IsStackPointer); |
| 385 } | 385 } |
| 386 | 386 |
| 387 int64_t sp() { return xreg(31, Reg31IsStackPointer); } | 387 int64_t sp() { return xreg(31, Reg31IsStackPointer); } |
| 388 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } | 388 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } |
| 389 int64_t fp() { | 389 int64_t fp() { |
| 390 return xreg(kFramePointerRegCode, Reg31IsStackPointer); | 390 return xreg(kFramePointerRegCode, Reg31IsStackPointer); |
| 391 } | 391 } |
| 392 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } | 392 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } |
| 393 | 393 |
| 394 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } | 394 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } |
| 395 | 395 |
| 396 template<typename T> | 396 template<typename T> |
| 397 T fpreg(unsigned code) const { | 397 T fpreg(unsigned code) const { |
| 398 ASSERT(code < kNumberOfRegisters); | 398 DCHECK(code < kNumberOfRegisters); |
| 399 return fpregisters_[code].Get<T>(); | 399 return fpregisters_[code].Get<T>(); |
| 400 } | 400 } |
| 401 | 401 |
| 402 // Common specialized accessors for the fpreg() template. | 402 // Common specialized accessors for the fpreg() template. |
| 403 float sreg(unsigned code) const { | 403 float sreg(unsigned code) const { |
| 404 return fpreg<float>(code); | 404 return fpreg<float>(code); |
| 405 } | 405 } |
| 406 | 406 |
| 407 uint32_t sreg_bits(unsigned code) const { | 407 uint32_t sreg_bits(unsigned code) const { |
| 408 return fpreg<uint32_t>(code); | 408 return fpreg<uint32_t>(code); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 423 default: | 423 default: |
| 424 UNREACHABLE(); | 424 UNREACHABLE(); |
| 425 return 0.0; | 425 return 0.0; |
| 426 } | 426 } |
| 427 } | 427 } |
| 428 | 428 |
| 429 // Write 'value' into a floating-point register. The value is zero-extended. | 429 // Write 'value' into a floating-point register. The value is zero-extended. |
| 430 // This behaviour matches AArch64 register writes. | 430 // This behaviour matches AArch64 register writes. |
| 431 template<typename T> | 431 template<typename T> |
| 432 void set_fpreg(unsigned code, T value) { | 432 void set_fpreg(unsigned code, T value) { |
| 433 ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); | 433 DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); |
| 434 ASSERT(code < kNumberOfFPRegisters); | 434 DCHECK(code < kNumberOfFPRegisters); |
| 435 fpregisters_[code].Set(value); | 435 fpregisters_[code].Set(value); |
| 436 } | 436 } |
| 437 | 437 |
| 438 // Common specialized accessors for the set_fpreg() template. | 438 // Common specialized accessors for the set_fpreg() template. |
| 439 void set_sreg(unsigned code, float value) { | 439 void set_sreg(unsigned code, float value) { |
| 440 set_fpreg(code, value); | 440 set_fpreg(code, value); |
| 441 } | 441 } |
| 442 | 442 |
| 443 void set_sreg_bits(unsigned code, uint32_t value) { | 443 void set_sreg_bits(unsigned code, uint32_t value) { |
| 444 set_fpreg(code, value); | 444 set_fpreg(code, value); |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 SimSystemRegister fpcr_; | 737 SimSystemRegister fpcr_; |
| 738 | 738 |
| 739 // Only a subset of FPCR features are supported by the simulator. This helper | 739 // Only a subset of FPCR features are supported by the simulator. This helper |
| 740 // checks that the FPCR settings are supported. | 740 // checks that the FPCR settings are supported. |
| 741 // | 741 // |
| 742 // This is checked when floating-point instructions are executed, not when | 742 // This is checked when floating-point instructions are executed, not when |
| 743 // FPCR is set. This allows generated code to modify FPCR for external | 743 // FPCR is set. This allows generated code to modify FPCR for external |
| 744 // functions, or to save and restore it when entering and leaving generated | 744 // functions, or to save and restore it when entering and leaving generated |
| 745 // code. | 745 // code. |
| 746 void AssertSupportedFPCR() { | 746 void AssertSupportedFPCR() { |
| 747 ASSERT(fpcr().FZ() == 0); // No flush-to-zero support. | 747 DCHECK(fpcr().FZ() == 0); // No flush-to-zero support. |
| 748 ASSERT(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only. | 748 DCHECK(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only. |
| 749 | 749 |
| 750 // The simulator does not support half-precision operations so fpcr().AHP() | 750 // The simulator does not support half-precision operations so fpcr().AHP() |
| 751 // is irrelevant, and is not checked here. | 751 // is irrelevant, and is not checked here. |
| 752 } | 752 } |
| 753 | 753 |
| 754 template <typename T> | 754 template <typename T> |
| 755 static int CalcNFlag(T result) { | 755 static int CalcNFlag(T result) { |
| 756 return (result >> (sizeof(T) * 8 - 1)) & 1; | 756 return (result >> (sizeof(T) * 8 - 1)) & 1; |
| 757 } | 757 } |
| 758 | 758 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 static void UnregisterCTryCatch() { | 829 static void UnregisterCTryCatch() { |
| 830 Simulator::current(Isolate::Current())->PopAddress(); | 830 Simulator::current(Isolate::Current())->PopAddress(); |
| 831 } | 831 } |
| 832 }; | 832 }; |
| 833 | 833 |
| 834 #endif // !defined(USE_SIMULATOR) | 834 #endif // !defined(USE_SIMULATOR) |
| 835 | 835 |
| 836 } } // namespace v8::internal | 836 } } // namespace v8::internal |
| 837 | 837 |
| 838 #endif // V8_ARM64_SIMULATOR_ARM64_H_ | 838 #endif // V8_ARM64_SIMULATOR_ARM64_H_ |
| OLD | NEW |