Skip to content

Instantly share code, notes, and snippets.

@rwy7
Last active April 30, 2019 15:05
Show Gist options
  • Save rwy7/d0b2506abac091c85bcdb48aa0e5b1fe to your computer and use it in GitHub Desktop.
Save rwy7/d0b2506abac091c85bcdb48aa0e5b1fe to your computer and use it in GitHub Desktop.
/*
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