Last active
April 30, 2019 15:05
-
-
Save rwy7/d0b2506abac091c85bcdb48aa0e5b1fe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
example of building a bytecode handler table. | |
My full implementation here: | |
https://github.com/rwy0717/intbuilder/blob/master/intbuilder/include/BytecodeHandlerTable.hpp | |
The difference: | |
In the example, the handlers all take a single arg: the bytecode builder. | |
In the real implementation, the handler's take their VM state as a second argument. | |
The BytecodeBuilderTable type is parameterized on the VMState type | |
This ensures that all handlers in a table use the same VM state type. | |
c++11 ism: | |
unique pointer is a smart-pointer that frees the referent in it's destructor. | |
It saves us from having to manually walk the table and free the different handlers, it happens automagically. | |
It's easy to replace with manual memory management. | |
*/ | |
#include <map> | |
#include <memory> | |
namespace OMR { | |
namespace JitBuilder { | |
class BytecodeBuilder; | |
/// Basic handler interface. | |
/// The handler table interacts with it's handlers through this interface. | |
class BytecodeHandler { | |
public: | |
virtual bool invoke(OMR::JitBuilder::BytecodeBuilder* builder) = 0; | |
virtual ~BytecodeHandler() = 0; | |
}; | |
/// A bytecode handler that wraps a function, or function-like object (aka functor). | |
/// An implementation of the BytecodeHandler interface, that defers to a wrapped function. | |
template <class F> | |
class BytecodeHandlerWrapper : public BytecodeHandler { | |
public: | |
/// The handler stores a copy of the target. | |
BytecodeHandlerWrapper(const F& function) : _function(function) {} | |
/// If F has a destructor, it will be called here. | |
virtual ~BytecodeHandlerWrapper() {} | |
/// The invoke call simply defers to the underlying function. | |
virtual bool invoke(OMR::JitBuilder::BytecodeBuilder* builder) { | |
return _function(builder); | |
} | |
private: | |
F _function; | |
}; | |
class BytecodeHandlerTable { | |
public: | |
/// associate a function with a bytecode. | |
template <typename F> | |
void assign(std::size_t bc, const F& function) { | |
_map[bc] = wrap(function); | |
} | |
private: | |
/// A unique pointer will free it's memory when it's destructed. | |
/// I'm using this as a utility so I don't have to free the handlers myself. | |
typedef std::unique_ptr<BytecodeHandler> BytecodeHandlerPtr; | |
typedef std::map<size_t, BytecodeHandlerPtr> Map; | |
/// Copy the handler into a BytecodeHandler wrapper. | |
template <typename F> | |
BytecodeHandlerPtr wrap(const F& function) { | |
return BytecodeHandlerPtr(new BytecodeHandlerWrapper<F>(function)); | |
} | |
Map _map; | |
}; | |
} // namespace JitBuilder | |
} // namespace OMR | |
bool handle_nop(OMR::JitBuilder::BytecodeBuilder* b) { | |
return true; | |
} | |
struct HandleAdd { | |
bool debug = true; | |
bool operator()(OMR::JitBuilder::BytecodeBuilder* b) { | |
if (debug) { | |
fprintf(stderr, "running handle add\n"); | |
} | |
return true; | |
} | |
}; | |
int main() { | |
OMR::JitBuilder::BytecodeHandlerTable table; | |
// register a function | |
table.assign(0, &handle_nop); | |
// register a struct | |
table.assign(1, HandleAdd()); | |
/// register a lambda | |
table.assign(2, [](OMR::JitBuilder::BytecodeBuilder* b) { | |
return true; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment