#include "BytecodeProgram.hpp"
#include "Bytecode.hpp"
#include "executable/Function.hpp"
#include "executable/Mangler.hpp"
#include "interpreter/Interpreter.hpp"
#include "runtime/PyCode.hpp"
#include "runtime/PyFrame.hpp"
#include "runtime/PyFunction.hpp"
#include "runtime/PyTraceback.hpp"
#include "runtime/PyTuple.hpp"
#include
using namespace py;
BytecodeProgram::BytecodeProgram(std::string filename, std::vector<:string> argv)
: Program(std::move(filename), std::move(argv))
{}
std::shared_ptr BytecodeProgram::create(FunctionBlocks &&func_blocks,
std::string filename,
std::vector<:string> argv)
{
auto program = std::shared_ptr(new BytecodeProgram{ filename, argv });
[[maybe_unused]] auto scope = VirtualMachine::the().heap().scoped_gc_pause();
std::vector functions_instruction_count;
functions_instruction_count.reserve(func_blocks.functions.size());
for (const auto &f : func_blocks.functions) {
functions_instruction_count.push_back(f.blocks.size());
}
auto &main_func = func_blocks.functions.front();
auto main_bytecode = std::make_unique(main_func.metadata.register_count,
main_func.metadata.varnames.size(),
main_func.metadata.stack_size,
main_func.metadata.function_name,
std::move(main_func.blocks),
std::move(main_func.instruction_locations),
program);
auto consts = PyTuple::create(main_func.metadata.consts);
if (consts.is_err()) { TODO(); }
auto main_function = PyCode::create(std::move(main_bytecode),
main_func.metadata.cell2arg,
main_func.metadata.arg_count,
main_func.metadata.cellvars,
consts.unwrap(),
main_func.metadata.filename,
main_func.metadata.first_line_number,
main_func.metadata.flags,
main_func.metadata.freevars,
main_func.metadata.positional_arg_count,
main_func.metadata.kwonly_arg_count,
main_func.metadata.stack_size,
"",
main_func.metadata.names,
main_func.metadata.nlocals,
main_func.metadata.varnames);
if (main_function.is_err()) { TODO(); }
program->m_main_function = main_function.unwrap();
for (size_t i = 1; i < func_blocks.functions.size(); ++i) {
auto &func = *std::next(func_blocks.functions.begin(), i);
auto bytecode = std::make_unique(func.metadata.register_count,
func.metadata.varnames.size(),
func.metadata.stack_size,
func.metadata.function_name,
std::move(func.blocks),
std::move(func.instruction_locations),
program);
consts = PyTuple::create(func.metadata.consts);
if (consts.is_err()) { TODO(); }
const auto &func_demangled_name =
Mangler::default_mangler().function_demangle(func.metadata.function_name);
auto code = PyCode::create(std::move(bytecode),
func.metadata.cell2arg,
func.metadata.arg_count,
func.metadata.cellvars,
consts.unwrap(),
func.metadata.filename,
func.metadata.first_line_number,
func.metadata.flags,
func.metadata.freevars,
func.metadata.positional_arg_count,
func.metadata.kwonly_arg_count,
func.metadata.stack_size,
func_demangled_name,
func.metadata.names,
func.metadata.nlocals,
func.metadata.varnames);
if (code.is_err()) { TODO(); }
program->m_functions.emplace_back(code.unwrap());
}
return program;
}
size_t BytecodeProgram::main_stack_size() const { return m_main_function->register_count(); }
InstructionVector::const_iterator BytecodeProgram::begin() const
{
// FIXME: assumes all functions are bytecode
ASSERT(m_main_function->function()->backend() == FunctionExecutionBackend::BYTECODE);
return static_cast(m_main_function->function().get())->begin();
}
InstructionVector::const_iterator BytecodeProgram::end() const
{
// FIXME: assumes all functions are bytecode
ASSERT(m_main_function->function()->backend() == FunctionExecutionBackend::BYTECODE);
return static_cast(m_main_function->function().get())->end();
}
std::string BytecodeProgram::to_string() const
{
std::stringstream ss;
for (const auto &func : m_functions) {
ss << func->function()->function_name() << ":\n";
ss << func->function()->to_string() << '\n';
}
ss << "main:\n";
ss << m_main_function->function()->to_string() << '\n';
return ss.str();
}
int BytecodeProgram::execute(VirtualMachine *vm)
{
auto &interpreter = vm->initialize_interpreter(shared_from_this());
auto result = m_main_function->function()->call(*vm, interpreter);
{
ScopedStack scoped_stack{ vm->push_frame(1, 0, 0) };
[[maybe_unused]] auto final_result = interpreter.finalise();
}
if (result.is_err()) {
// The exception propagated all the way out; the eval loop already popped it
// off the (now-clean) exception stack as it unwound, so use the result value
// directly rather than popping again.
auto *exception = result.unwrap_err();
std::cout << exception->format_traceback() << std::endl;
}
return result.is_ok() ? EXIT_SUCCESS : EXIT_FAILURE;
}
PyObject *BytecodeProgram::as_pyfunction(const std::string &function_name,
const std::vector &default_values,
const std::vector &kw_default_values,
PyTuple *closure) const
{
for (const auto &backend : m_backends) {
if (auto *f =
backend->as_pyfunction(function_name, default_values, kw_default_values, closure)) {
return f;
}
}
if (auto it = std::find_if(m_functions.begin(),
m_functions.end(),
[&function_name](const auto &f) {
ASSERT(f->function());
return f->function()->function_name() == function_name;
});
it != m_functions.end()) {
auto *code = *it;
return VirtualMachine::the().heap().allocate(default_values,
kw_default_values,
code,
closure,
VirtualMachine::the().interpreter().execution_frame()->globals());
}
return nullptr;
}
PyObject *BytecodeProgram::main_function() { return m_main_function; }
void BytecodeProgram::add_backend(std::shared_ptr other)
{
m_backends.push_back(std::move(other));
}
std::string FunctionBlock::to_string() const
{
std::ostringstream os;
os << "Function name: " << metadata.function_name << '\n';
for (const auto &ins : blocks) { os << " " << ins->to_string() << '\n'; }
return os.str();
}
void BytecodeProgram::visit_functions(Cell::Visitor &visitor) const
{
visitor.visit(*const_cast(m_main_function));
for (auto &f : m_functions) { visitor.visit(*const_cast(f)); };
}
std::vector BytecodeProgram::serialize() const
{
std::vector result;
const auto main_func_serialized = m_main_function->serialize();
result.insert(result.end(), main_func_serialized.begin(), main_func_serialized.end());
for (const auto &func : m_functions) {
const auto func_serialized = func->serialize();
result.insert(result.end(), func_serialized.begin(), func_serialized.end());
}
// TODO: Add support to serialize functions from different backends
ASSERT(m_backends.empty());
return result;
}
std::shared_ptr BytecodeProgram::deserialize(const std::vector &buffer)
{
[[maybe_unused]] auto scope = VirtualMachine::the().heap().scoped_gc_pause();
auto program = std::shared_ptr(new BytecodeProgram);
auto span = std::span{ buffer };
auto deserialized_result = PyCode::deserialize(span, program);
ASSERT(deserialized_result.first.is_ok());
program->m_main_function = deserialized_result.first.unwrap();
spdlog::debug(
"Deserialized main function:\n{}\n\n", program->m_main_function->function()->to_string());
while (!span.empty()) {
deserialized_result = PyCode::deserialize(span, program);
ASSERT(deserialized_result.first.is_ok());
program->m_functions.push_back(deserialized_result.first.unwrap());
spdlog::debug("Deserialized function {}:\n{}\n\n",
program->m_functions.back()->function()->function_name(),
program->m_functions.back()->function()->to_string());
}
return program;
}