| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2014 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-07 18:10:39 -05:00
										 |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 16:39:47 -04:00
										 |  |  | #include "Common/Assert.h"
 | 
					
						
							| 
									
										
										
										
											2017-01-07 18:10:39 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | #include "Common/MemoryUtil.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 16:13:54 -04:00
										 |  |  | #include "Common/NonCopyable.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Everything that needs to generate code should inherit from this.
 | 
					
						
							|  |  |  | // You get memory management for free, plus, you can use all emitter functions without
 | 
					
						
							|  |  |  | // having to prefix them with gen-> or something similar.
 | 
					
						
							|  |  |  | // Example implementation:
 | 
					
						
							|  |  |  | // class JIT : public CodeBlock<ARMXEmitter> {}
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | template <class T> | 
					
						
							|  |  |  | class CodeBlock : public T, NonCopyable | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | { | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // A privately used function to set the executable RAM space to something invalid.
 | 
					
						
							|  |  |  |   // For debugging usefulness it should be used to set the RAM to a host specific breakpoint
 | 
					
						
							|  |  |  |   // instruction
 | 
					
						
							|  |  |  |   virtual void PoisonMemory() = 0; | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							| 
									
										
										
										
											2016-08-06 13:09:21 -04:00
										 |  |  |   u8* region = nullptr; | 
					
						
							|  |  |  |   size_t region_size = 0; | 
					
						
							|  |  |  |   size_t parent_region_size = 0; | 
					
						
							| 
									
										
										
										
											2015-08-07 22:08:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 13:09:21 -04:00
										 |  |  |   bool m_has_child = false; | 
					
						
							|  |  |  |   bool m_is_child = false; | 
					
						
							|  |  |  |   CodeBlock* m_child = nullptr; | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   virtual ~CodeBlock() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (region) | 
					
						
							|  |  |  |       FreeCodeSpace(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Call this before you generate any code.
 | 
					
						
							| 
									
										
										
										
											2017-01-07 18:10:39 -05:00
										 |  |  |   void AllocCodeSpace(size_t size, bool need_low = true) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |     region_size = size; | 
					
						
							| 
									
										
										
										
											2016-08-07 13:03:07 -04:00
										 |  |  |     region = static_cast<u8*>(Common::AllocateExecutableMemory(region_size, need_low)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     T::SetCodePtr(region); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Always clear code space with breakpoints, so that if someone accidentally executes
 | 
					
						
							|  |  |  |   // uninitialized, it just breaks into the debugger.
 | 
					
						
							|  |  |  |   void ClearCodeSpace() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PoisonMemory(); | 
					
						
							|  |  |  |     ResetCodePtr(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
 | 
					
						
							|  |  |  |   void FreeCodeSpace() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-08-07 13:03:07 -04:00
										 |  |  |     Common::FreeMemoryPages(region, region_size); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     region = nullptr; | 
					
						
							|  |  |  |     region_size = 0; | 
					
						
							|  |  |  |     parent_region_size = 0; | 
					
						
							|  |  |  |     if (m_has_child) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       m_child->region = nullptr; | 
					
						
							|  |  |  |       m_child->region_size = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 18:05:28 -05:00
										 |  |  |   bool IsInSpace(const u8* ptr) const { return ptr >= region && ptr < (region + region_size); } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Cannot currently be undone. Will write protect the entire code region.
 | 
					
						
							|  |  |  |   // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
 | 
					
						
							| 
									
										
										
										
											2016-08-07 13:03:07 -04:00
										 |  |  |   void WriteProtect() { Common::WriteProtectMemory(region, region_size, true); } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   void ResetCodePtr() { T::SetCodePtr(region); } | 
					
						
							|  |  |  |   size_t GetSpaceLeft() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return (m_has_child ? parent_region_size : region_size) - (T::GetCodePtr() - region); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool IsAlmostFull() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // This should be bigger than the biggest block ever.
 | 
					
						
							|  |  |  |     return GetSpaceLeft() < 0x10000; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   void AddChildCodeSpace(CodeBlock* child, size_t size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, !m_has_child, "Already have a child! Can't have another!"); | 
					
						
							|  |  |  |     m_child = child; | 
					
						
							|  |  |  |     m_has_child = true; | 
					
						
							|  |  |  |     m_child->m_is_child = true; | 
					
						
							|  |  |  |     u8* child_region = region + region_size - size; | 
					
						
							|  |  |  |     m_child->region = child_region; | 
					
						
							|  |  |  |     m_child->region_size = size; | 
					
						
							|  |  |  |     m_child->ResetCodePtr(); | 
					
						
							|  |  |  |     parent_region_size = region_size - size; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-04-09 01:22:52 -05:00
										 |  |  | }; |