From 826a9e0152f6ae1422f2e4e69f9dd5dc8a2b7822 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 18 May 2014 14:10:47 +0200 Subject: [PATCH] MMIO: Lazy-initialize read/write handlers since most are not actually used --- Source/Core/Core/HW/MMIO.cpp | 26 +++++++++++++---------- Source/Core/Core/HW/MMIO.h | 12 +++++------ Source/Core/Core/HW/MMIOHandlers.h | 34 ++++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/HW/MMIO.cpp b/Source/Core/Core/HW/MMIO.cpp index f8cbe9ee18..d1b37e5c54 100644 --- a/Source/Core/Core/HW/MMIO.cpp +++ b/Source/Core/Core/HW/MMIO.cpp @@ -224,8 +224,8 @@ ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_ { typedef typename SmallerAccessSize::value ST; - const ReadHandler* high_part; - const ReadHandler* low_part; + ReadHandler* high_part; + ReadHandler* low_part; mmio->GetHandlerForRead(high_part_addr, &high_part); mmio->GetHandlerForRead(low_part_addr, &low_part); @@ -241,8 +241,8 @@ WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 lo { typedef typename SmallerAccessSize::value ST; - const WriteHandler* high_part; - const WriteHandler* low_part; + WriteHandler* high_part; + WriteHandler* low_part; mmio->GetHandlerForWrite(high_part_addr, &high_part); mmio->GetHandlerForWrite(low_part_addr, &low_part); @@ -258,7 +258,7 @@ ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift) { typedef typename LargerAccessSize::value LT; - const ReadHandler* large; + ReadHandler* large; mmio->GetHandlerForRead(larger_addr, &large); // TODO(delroth): optimize @@ -271,9 +271,8 @@ ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift) // redundant code between these two classes but trying to abstract it away // brings more trouble than it fixes. template -ReadHandler::ReadHandler() : m_Method(nullptr) +ReadHandler::ReadHandler() { - ResetMethod(InvalidRead()); } template @@ -289,8 +288,11 @@ ReadHandler::~ReadHandler() } template -void ReadHandler::Visit(ReadHandlingMethodVisitor& visitor) const +void ReadHandler::Visit(ReadHandlingMethodVisitor& visitor) { + if (!m_Method) + InitializeInvalid(); + m_Method->AcceptReadVisitor(visitor); } @@ -325,9 +327,8 @@ void ReadHandler::ResetMethod(ReadHandlingMethod* method) } template -WriteHandler::WriteHandler() : m_Method(nullptr) +WriteHandler::WriteHandler() { - ResetMethod(InvalidWrite()); } template @@ -343,8 +344,11 @@ WriteHandler::~WriteHandler() } template -void WriteHandler::Visit(WriteHandlingMethodVisitor& visitor) const +void WriteHandler::Visit(WriteHandlingMethodVisitor& visitor) { + if (!m_Method) + InitializeInvalid(); + m_Method->AcceptWriteVisitor(visitor); } diff --git a/Source/Core/Core/HW/MMIO.h b/Source/Core/Core/HW/MMIO.h index 28fe19ba5a..721689fb54 100644 --- a/Source/Core/Core/HW/MMIO.h +++ b/Source/Core/Core/HW/MMIO.h @@ -105,7 +105,7 @@ public: // Note that for reads we cannot simply return the read value because C++ // allows overloading only with parameter types, not return types. #define READ_FUNC(Size) \ - void Read(u32 addr, u##Size* val) const \ + void Read(u32 addr, u##Size* val) \ { \ u32 id = UniqueID(addr) / sizeof (u##Size); \ *val = m_Read##Size##Handlers[id].Read(addr); \ @@ -114,7 +114,7 @@ public: #undef READ_FUNC #define WRITE_FUNC(Size) \ - void Write(u32 addr, u##Size val) const \ + void Write(u32 addr, u##Size val) \ { \ u32 id = UniqueID(addr) / sizeof (u##Size); \ m_Write##Size##Handlers[id].Write(addr, val); \ @@ -133,11 +133,11 @@ public: // value. This second variant is needed because C++ doesn't do overloads // based on return type but only based on argument types. #define GET_HANDLERS_FUNC(Type, Size) \ - const Type##Handler& GetHandlerFor##Type##Size(u32 addr) const \ + Type##Handler& GetHandlerFor##Type##Size(u32 addr) \ { \ return m_##Type##Size##Handlers[UniqueID(addr) / sizeof (u##Size)]; \ } \ - void GetHandlerFor##Type(u32 addr, const Type##Handler** h) const \ + void GetHandlerFor##Type(u32 addr, Type##Handler** h) \ { \ *h = &GetHandlerFor##Type##Size(addr); \ } @@ -147,8 +147,8 @@ public: // Dummy 64 bits variants of these functions. While 64 bits MMIO access is // not supported, we need these in order to make the code compile. - void Read(u32 addr, u64* val) const { _dbg_assert_(MEMMAP, 0); } - void Write(u32 addr, u64 val) const { _dbg_assert_(MEMMAP, 0); } + void Read(u32 addr, u64* val) { _dbg_assert_(MEMMAP, 0); } + void Write(u32 addr, u64 val) { _dbg_assert_(MEMMAP, 0); } private: // These arrays contain the handlers for each MMIO access type: read/write diff --git a/Source/Core/Core/HW/MMIOHandlers.h b/Source/Core/Core/HW/MMIOHandlers.h index 7afe9f60b5..8fc3c25e6d 100644 --- a/Source/Core/Core/HW/MMIOHandlers.h +++ b/Source/Core/Core/HW/MMIOHandlers.h @@ -115,10 +115,16 @@ public: ~ReadHandler(); // Entry point for read handling method visitors. - void Visit(ReadHandlingMethodVisitor& visitor) const; + void Visit(ReadHandlingMethodVisitor& visitor); - T Read(u32 addr) const + T Read(u32 addr) { + // Check if the handler has already been initialized. For real + // handlers, this will always be the case, so this branch should be + // easily predictable. + if (!m_Method) + InitializeInvalid(); + return m_ReadFunc(addr); } @@ -127,6 +133,13 @@ public: void ResetMethod(ReadHandlingMethod* method); private: + // Initialize this handler to an invalid handler. Done lazily to avoid + // useless initialization of thousands of unused handler objects. + void InitializeInvalid() + { + ResetMethod(InvalidRead()); + } + std::unique_ptr> m_Method; std::function m_ReadFunc; }; @@ -142,10 +155,16 @@ public: ~WriteHandler(); // Entry point for write handling method visitors. - void Visit(WriteHandlingMethodVisitor& visitor) const; + void Visit(WriteHandlingMethodVisitor& visitor); - void Write(u32 addr, T val) const + void Write(u32 addr, T val) { + // Check if the handler has already been initialized. For real + // handlers, this will always be the case, so this branch should be + // easily predictable. + if (!m_Method) + InitializeInvalid(); + m_WriteFunc(addr, val); } @@ -155,6 +174,13 @@ public: void ResetMethod(WriteHandlingMethod* method); private: + // Initialize this handler to an invalid handler. Done lazily to avoid + // useless initialization of thousands of unused handler objects. + void InitializeInvalid() + { + ResetMethod(InvalidWrite()); + } + std::unique_ptr> m_Method; std::function m_WriteFunc; };