commit 581de5ac65753b00541086820ebd15f3eaf2d7e3
parent 92f433cb3835b8b0b70ecc682b69f1b3d231ac8d
Author: Mohammad-Reza Nabipoor <mnabipoor@gnu.org>
Date: Sat, 28 May 2022 00:49:16 +0430
Add Jittery VM + support code
Diffstat:
M | .gitignore | | | 1 | + |
M | Makefile | | | 36 | ++++++++++++++++++++++++++++++++---- |
A | ast.cpp | | | 124 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | ast.hpp | | | 105 | ++++++++++--------------------------------------------------------------------- |
A | cgen.cpp | | | 276 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | cgen.hpp | | | 167 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
M | cgen.test.cpp | | | 114 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
A | jitter.patch | | | 97 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | toctave.jitter | | | 136 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
9 files changed, 870 insertions(+), 186 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1 +1,2 @@
*.test
+vm/
diff --git a/Makefile b/Makefile
@@ -1,15 +1,43 @@
+JITTER_DISPATCH = switch
+JITTER_PREFIX ?= $(HOME)/usr
+
CXXFLAGS += -Wall -Wextra -std=c++17 -g3 -fsanitize=address
-CPPFLAGS += -I.
+CPPFLAGS += -I . -I $(JITTER_PREFIX)/include/
+LDFLAGS += -lm
+
+#---
+
+J = ${JITTER_PREFIX}/bin/jitter
+JC = ${JITTER_PREFIX}/bin/jitter-config --dispatch=$(JITTER_DISPATCH)
+
+JCPPFLAGS += -I vm/ $(shell $(JC) --cppflags)
+JCFLAGS += $(shell $(JC) --cflags)
+JLDFLAGS += $(shell $(JC) --ldflags --ldadd)
BINS = ast.test cgen.test
+VM = vm/toctave-vm1.c vm/toctave-vm2.c vm/toctave-vm.h
+VM_OBJS = vm/toctave-vm1.o vm/toctave-vm2.o
all: $(BINS)
-ast.test: ast.test.cpp
-cgen.test: cgen.test.cpp
+ast.test: ast.test.cpp ast.cpp ast.hpp
+ $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) $< ast.cpp
+
+cgen.test: cgen.hpp
+cgen.test: cgen.test.cpp cgen.cpp ast.cpp ast.hpp $(VM_OBJS)
+ $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) $< cgen.cpp ast.cpp $(VM_OBJS) \
+ $(JCPPFLAGS) $(JLDFLAGS)
+
+$(VM) &: toctave.jitter
+ $(J) -o vm/ $<
+
+vm/toctave-vm1.o: vm/toctave-vm1.c
+ $(CC) -c -o $@ $< $(CPPFLAGS) $(CFLAGS) $(JCPPFLAGS) $(JLDFLAGS)
+vm/toctave-vm2.o: vm/toctave-vm2.c
+ $(CC) -c -o $@ $< $(CPPFLAGS) $(CFLAGS) $(JCPPFLAGS) $(JCFLAGS) $(JLDFLAGS)
.PHONY: clean
clean:
- rm -f $(BINS)
+ rm -f $(BINS) $(VM)
diff --git a/ast.cpp b/ast.cpp
@@ -0,0 +1,124 @@
+
+#include "ast.hpp"
+
+namespace ast {
+
+std::ostream&
+operator<<(std::ostream& os, const Num& n)
+{
+ os << "Num{ " << n.num << " }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Op& o)
+{
+ os << "Op{ " << o.op << " }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Id& i)
+{
+ os << "Id{ " << i.id << " }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Str& s)
+{
+ os << "Str{ \"" << s.str << "\" }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const As& a)
+{
+ os << "As{ " << a.id << " }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Call& c)
+{
+ os << "Call{ " << c.id << " }";
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Node& n)
+{
+ if (std::holds_alternative<Num>(n))
+ os << std::get<Num>(n);
+ else if (std::holds_alternative<Op>(n))
+ os << std::get<Op>(n);
+ else if (std::holds_alternative<Id>(n))
+ os << std::get<Id>(n);
+ else if (std::holds_alternative<Str>(n))
+ os << std::get<Str>(n);
+ else if (std::holds_alternative<As>(n))
+ os << std::get<As>(n);
+ else if (std::holds_alternative<Call>(n))
+ os << std::get<Call>(n);
+ return os;
+}
+
+Nodes
+mknum(double n)
+{
+ Nodes f;
+
+ f.insert(f.end(), Num{ n });
+ return f;
+}
+
+Nodes
+mkop(Op op, Nodes lhs, Nodes rhs)
+{
+ Nodes f;
+ auto it{ stlab::trailing_of(f.insert(f.end(), std::move(op))) };
+
+ f.splice(it, lhs);
+ f.splice(it, rhs);
+ return f;
+}
+
+Nodes
+mkid(Id id)
+{
+ Nodes f;
+
+ f.insert(f.end(), std::move(id));
+ return f;
+}
+
+Nodes
+mkstr(Str str)
+{
+ Nodes f;
+
+ f.insert(f.end(), std::move(str));
+ return f;
+}
+
+Nodes
+mkass(Id id, Nodes expr)
+{
+ Nodes f;
+ auto it{ stlab::trailing_of(f.insert(f.end(), ast::As{ std::move(id) })) };
+
+ f.splice(it, expr);
+ return f;
+}
+
+Nodes
+mkcall(Id id, Nodes args)
+{
+ Nodes f;
+ auto it{ stlab::trailing_of(f.insert(f.end(), ast::Call{ std::move(id) })) };
+
+ f.splice(it, args);
+ return f;
+}
+
+} // namespace ast
diff --git a/ast.hpp b/ast.hpp
@@ -43,124 +43,45 @@ struct Call
using Node = std::variant<Num, Op, Id, Str, As, Call>;
std::ostream&
-operator<<(std::ostream& os, const Num& n)
-{
- os << "Num{ " << n.num << " }";
- return os;
-}
+operator<<(std::ostream& os, const Num& n);
std::ostream&
-operator<<(std::ostream& os, const Op& o)
-{
- os << "Op{ " << o.op << " }";
- return os;
-}
+operator<<(std::ostream& os, const Op& o);
std::ostream&
-operator<<(std::ostream& os, const Id& i)
-{
- os << "Id{ " << i.id << " }";
- return os;
-}
+operator<<(std::ostream& os, const Id& i);
std::ostream&
-operator<<(std::ostream& os, const Str& s)
-{
- os << "Str{ \"" << s.str << "\" }";
- return os;
-}
+operator<<(std::ostream& os, const Str& s);
std::ostream&
-operator<<(std::ostream& os, const As& a)
-{
- os << "As{ " << a.id << " }";
- return os;
-}
+operator<<(std::ostream& os, const As& a);
std::ostream&
-operator<<(std::ostream& os, const Call& c)
-{
- os << "Call{ " << c.id << " }";
- return os;
-}
+operator<<(std::ostream& os, const Call& c);
std::ostream&
-operator<<(std::ostream& os, const Node& n)
-{
- if (std::holds_alternative<Num>(n))
- os << std::get<Num>(n);
- else if (std::holds_alternative<Op>(n))
- os << std::get<Op>(n);
- else if (std::holds_alternative<Id>(n))
- os << std::get<Id>(n);
- else if (std::holds_alternative<Str>(n))
- os << std::get<Str>(n);
- else if (std::holds_alternative<As>(n))
- os << std::get<As>(n);
- else if (std::holds_alternative<Call>(n))
- os << std::get<Call>(n);
- return os;
-}
+operator<<(std::ostream& os, const Node& n);
using Nodes = stlab::forest<Node>;
using NodesIter = Nodes::iterator;
Nodes
-mknum(double n)
-{
- Nodes f;
-
- f.insert(f.end(), Num{ n });
- return f;
-}
+mknum(double n);
Nodes
-mkop(Op op, Nodes lhs, Nodes rhs)
-{
- Nodes f;
- auto it{ stlab::trailing_of(f.insert(f.end(), std::move(op))) };
-
- f.splice(it, lhs);
- f.splice(it, rhs);
- return f;
-}
+mkop(Op op, Nodes lhs, Nodes rhs);
Nodes
-mkid(Id id)
-{
- Nodes f;
-
- f.insert(f.end(), std::move(id));
- return f;
-}
+mkid(Id id);
Nodes
-mkstr(Str str)
-{
- Nodes f;
-
- f.insert(f.end(), std::move(str));
- return f;
-}
+mkstr(Str str);
Nodes
-mkass(Id id, Nodes expr)
-{
- Nodes f;
- auto it{ stlab::trailing_of(f.insert(f.end(), ast::As{ std::move(id) })) };
-
- f.splice(it, expr);
- return f;
-}
+mkass(Id id, Nodes expr);
Nodes
-mkcall(Id id, Nodes args)
-{
- Nodes f;
- auto it{ stlab::trailing_of(f.insert(f.end(), ast::Call{ std::move(id) })) };
-
- f.splice(it, args);
- return f;
-}
+mkcall(Id id, Nodes args);
} // namespace ast
diff --git a/cgen.cpp b/cgen.cpp
@@ -0,0 +1,276 @@
+
+#include "cgen.hpp"
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <vector>
+
+namespace {
+
+template<typename... Ts>
+struct overloaded : Ts...
+{
+ using Ts::operator()...;
+};
+template<typename... Ts>
+overloaded(Ts...) -> overloaded<Ts...>;
+
+class JPrinter
+{
+private:
+ std::unique_ptr<void, void (*)(void*)> pcontext;
+
+public:
+ JPrinter()
+ : pcontext(jitter_print_context_make_memory(), [](void* p) {
+ auto ctx{ reinterpret_cast<jitter_print_context>(p) };
+
+ jitter_print_context_destroy(ctx);
+ })
+ {}
+
+ jitter_print_context ctx()
+ {
+ return reinterpret_cast<jitter_print_context>(pcontext.get());
+ }
+
+ std::string buffer()
+ {
+ auto str{ jitter_print_context_get_memory(ctx(), /*length_p*/ nullptr) };
+ std::string s{ str };
+
+ free(str);
+ return s;
+ }
+};
+
+} // anonymous namespace
+
+namespace cgen {
+
+std::string
+sexpr(ast::NodesIter first, ast::NodesIter last)
+{
+ std::ostringstream oss;
+
+ while (first != last) {
+ std::visit(overloaded{
+ [&](const ast::Num& n) { oss << n.num; },
+ [&](const ast::Op& op) {
+ auto f{ ++stlab::leading_of(first) };
+ auto l{ stlab::trailing_of(first) };
+ auto count{ 0u };
+
+ oss << "(" << op.op;
+ while (f != l) {
+ auto n{ ++stlab::trailing_of(f) };
+ oss << " " << sexpr(f, n);
+ f = n;
+ ++count;
+ }
+ assert(count == 2);
+ oss << ")";
+ },
+ [&](const ast::Id& id) { oss << id.id; },
+ [&](const ast::Str& str) { oss << '"' << str.str << '"'; },
+ [&](const ast::As& as) {
+ auto f{ ++stlab::leading_of(first) };
+ auto l{ stlab::trailing_of(first) };
+
+ assert(stlab::has_children(first));
+
+ oss << "(setq " << as.id.id << " ";
+ oss << sexpr(f, ++stlab::trailing_of(f)) << ")";
+ },
+ [&](const ast::Call& call) {
+ auto f{ ++stlab::leading_of(first) };
+ auto l{ stlab::trailing_of(first) };
+
+ assert(stlab::has_children(first));
+
+ oss << "(" << call.id.id;
+ while (f != l) {
+ auto n{ ++stlab::trailing_of(f) };
+ oss << " " << sexpr(f, n);
+ f = n;
+ }
+ oss << ")";
+ },
+ },
+ *first);
+
+ first = ++stlab::trailing_of(first);
+ }
+
+ return oss.str();
+}
+
+//--- Jittery VM
+
+JExecRoutine::JExecRoutine(struct toctave_mutable_routine* r)
+ : er(toctave_make_executable_routine(r),
+ [](struct toctave_executable_routine* p) {
+ toctave_destroy_executable_routine(p);
+ })
+ , state(toctave_state_make(),
+ [](struct toctave_state* s) { toctave_state_destroy(s); })
+{}
+
+void
+JExecRoutine::exec()
+{
+ toctave_execute_executable_routine(er.get(), state.get());
+}
+
+bool
+JExecRoutine::exec_continue()
+{
+ auto point{ TOCTAVE_STATE_RUNTIME_FIELD(state.get(), point) };
+
+ if (point == nullptr)
+ return false;
+ toctave_branch_to_program_point(point, state.get());
+ return true;
+}
+
+double
+JExecRoutine::result()
+{
+ return TOCTAVE_STATE_RUNTIME_FIELD(state.get(), result);
+}
+
+//---
+
+JRoutine::JRoutine()
+ : r(toctave_make_mutable_routine(), [](struct toctave_mutable_routine* p) {
+ toctave_destroy_mutable_routine(p);
+ })
+{}
+
+JExecRoutine
+JRoutine::mkexec()
+{
+ return JExecRoutine(r.get());
+}
+
+JRoutine::label_t
+JRoutine::mklabel()
+{
+ return toctave_fresh_label(r.get());
+}
+
+JRoutine::label_t
+JRoutine::label(JRoutine::label_t l)
+{
+ toctave_mutable_routine_append_label(r.get(), l);
+ return l;
+}
+
+JRoutine::label_t
+JRoutine::label()
+{
+ return label(mklabel());
+}
+
+void
+JRoutine::push(double d)
+{
+ static_assert(sizeof(void*) == sizeof(double),
+ "We're using double as the type of stack elements; to make "
+ "the implementation easier, we expect a 64-bit platform");
+ uintptr_t num;
+
+ memcpy(&num, &d, sizeof(d)); // copy the bits of double into the uint
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), push);
+ toctave_mutable_routine_append_unsigned_literal_parameter(r.get(), num);
+}
+
+void
+JRoutine::pop()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), pop);
+}
+
+void
+JRoutine::drop()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), drop);
+}
+
+void
+JRoutine::pow()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), pow);
+}
+
+void
+JRoutine::mul()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), mul);
+}
+
+void
+JRoutine::div()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), div);
+}
+
+void
+JRoutine::add()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), add);
+}
+
+void
+JRoutine::sub()
+{
+ TOCTAVE_MUTABLE_ROUTINE_APPEND_INSTRUCTION(r.get(), sub);
+}
+
+std::string
+disasm(const JRoutine& r)
+{
+ JPrinter jprinter;
+
+ toctave_mutable_routine_print(jprinter.ctx(), r.r.get());
+ return jprinter.buffer();
+}
+
+std::string
+disasm(const JExecRoutine& er)
+{
+ JPrinter jprinter;
+
+ toctave_executable_routine_disassemble(
+ jprinter.ctx(), er.er.get(), true, "objdump", nullptr);
+ return jprinter.buffer();
+}
+
+//--- codegen
+
+JRoutine
+jitter(ast::NodesIter first, ast::NodesIter last)
+{
+ JRoutine r;
+
+ while (first != last) {
+ for (const auto& stmt : stlab::child_range(stlab::leading_of(first))) {
+ std::visit(overloaded{
+ [&](const ast::Num&) {},
+ [&](const ast::Op&) {},
+ [&](const ast::Id&) {},
+ [&](const ast::Str&) {},
+ [&](const ast::As&) {},
+ [&](const ast::Call&) {},
+ },
+ stmt);
+ }
+ first = ++stlab::trailing_of(first);
+ }
+
+ return r;
+}
+
+} // namespace cgen
diff --git a/cgen.hpp b/cgen.hpp
@@ -1,103 +1,94 @@
#pragma once
-#include <sstream>
+#include <memory>
#include "ast.hpp"
+// Use the VM generated by Jitter
+extern "C"
+{
+#define restrict
+#include "vm/toctave-vm.h"
+#undef restrict
+}
+
namespace cgen {
-template<typename... Ts>
-struct overloaded : Ts...
-{
- using Ts::operator()...;
-};
-template<typename... Ts>
-overloaded(Ts...) -> overloaded<Ts...>;
+// Generates S-Expression equivalent of input AST
+std::string
+sexpr(ast::NodesIter first, ast::NodesIter last);
+
+//--- Jittery VM
-struct jroutine
-{};
+class JExecRoutine;
+class JRoutine;
-jroutine
-jitter(const ast::Nodes& ns)
+std::string disasm(const JExecRoutine& er);
+std::string disasm(const JRoutine& r);
+
+// Jitter Executable Routine
+class JExecRoutine
{
- jroutine r;
- auto first{ ns.begin() };
- auto last{ ns.end() };
-
- while (first != last) {
- for (const auto& stmt : stlab::child_range(stlab::leading_of(first))) {
- std::visit(overloaded{
- [&](const ast::Num&) {},
- [&](const ast::Op&) {},
- [&](const ast::Id&) {},
- [&](const ast::Str&) {},
- [&](const ast::As&) {},
- [&](const ast::Call&) {},
- },
- stmt);
- }
- first = ++stlab::trailing_of(first);
- }
-
- return r;
-}
+private:
+ std::unique_ptr<struct toctave_executable_routine,
+ void (*)(struct toctave_executable_routine*)>
+ er;
+ std::unique_ptr<struct toctave_state, void(*)(struct toctave_state*)> state;
-std::string
-sexpr(ast::NodesIter first, ast::NodesIter last)
+public:
+ JExecRoutine() = default;
+ JExecRoutine(struct toctave_mutable_routine*);
+
+ friend std::string disasm(const JExecRoutine& er);
+
+ void exec();
+ bool exec_continue();
+
+ double result();
+};
+
+class JRoutine
{
- std::ostringstream oss;
-
- while (first != last) {
- std::visit(overloaded{
- [&](const ast::Num& n) { oss << n.num; },
- [&](const ast::Op& op) {
- auto f{ ++stlab::leading_of(first) };
- auto l{ stlab::trailing_of(first) };
- auto count{ 0u };
-
- oss << "(" << op.op;
- while (f != l) {
- auto n{ ++stlab::trailing_of(f) };
- oss << " " << sexpr(f, n);
- f = n;
- ++count;
- }
- assert(count == 2);
- oss << ")";
- },
- [&](const ast::Id& id) { oss << id.id; },
- [&](const ast::Str& str) { oss << '"' << str.str << '"'; },
- [&](const ast::As& as) {
- auto f{ ++stlab::leading_of(first) };
- auto l{ stlab::trailing_of(first) };
-
- assert(stlab::has_children(first));
-
- oss << "(setq " << as.id.id << " ";
- oss << sexpr(f, ++stlab::trailing_of(f)) << ")";
- },
- [&](const ast::Call& call) {
- auto f{ ++stlab::leading_of(first) };
- auto l{ stlab::trailing_of(first) };
-
- assert(stlab::has_children(first));
-
- oss << "(" << call.id.id;
- while (f != l) {
- auto n{ ++stlab::trailing_of(f) };
- oss << " " << sexpr(f, n);
- f = n;
- }
- oss << ")";
- },
- },
- *first);
-
- first = ++stlab::trailing_of(first);
- }
-
- return oss.str();
-}
+private:
+ std::unique_ptr<struct toctave_mutable_routine,
+ void (*)(struct toctave_mutable_routine*)>
+ r;
+
+public:
+ using label_t = toctave_label;
+
+ JRoutine();
+
+ friend std::string disasm(const JRoutine& r);
+ JExecRoutine mkexec();
+
+ //--- label manipulation
+
+ label_t mklabel();
+ label_t label(label_t l);
+ label_t label();
+
+ //--- instructions
+
+ // stack manipulation
+ void push(double d);
+ void pop();
+ void drop();
+
+ // arithmetic
+ void pow();
+ void mul();
+ void div();
+ void add();
+ void sub();
+
+ // branching
+ // ...
+};
+
+// Generates code for the VM generated by Jitter
+JRoutine
+jitter(ast::NodesIter first, ast::NodesIter last);
} // namespace cgen
diff --git a/cgen.test.cpp b/cgen.test.cpp
@@ -7,7 +7,7 @@
namespace {
void
-cgen_1()
+cgen_sexpr()
{
auto i{ 0 };
auto p = [&](const auto& s) {
@@ -23,6 +23,104 @@ cgen_1()
p(s);
assert(s == "(+ 1 2)");
}
+
+ {
+ ast::Nodes ass1{ ast::mkass(
+ ast::Id{ "x" },
+ ast::mkop(ast::Op{ '+' },
+ ast::mkop(ast::Op{ '/' }, ast::mknum(1), ast::mknum(2)),
+ ast::mkop(ast::Op{ '*' }, ast::mknum(3), ast::mknum(4)))) };
+ auto s{ cgen::sexpr(ass1.begin(), ass1.end()) };
+
+ p(s);
+ assert(s == "(setq x (+ (/ 1 2) (* 3 4)))");
+ }
+
+ {
+ ast::Nodes eval1{ ast::mkcall(ast::Id{ "eval" },
+ ast::mkstr(ast::Str{ "y = 1 + x" })) };
+ auto s{ cgen::sexpr(eval1.begin(), eval1.end()) };
+
+ p(s);
+ assert(s == "(eval \"y = 1 + x\")");
+ }
+}
+
+void
+cgen_jroutine()
+{
+ auto i{ 0 };
+ auto p = [&](const auto& s) {
+ std::cout << "# Disasm " << i << " {\n" << s << "# Disasm " << i << " }\n";
+ ++i;
+ };
+
+ {
+ cgen::JRoutine r;
+
+ r.push(1.0);
+ r.push(2.0);
+ r.add();
+ r.pop(); /* Moves the result on top of the stack onto `result` */
+
+ auto d{ cgen::disasm(r) };
+
+ p(d);
+ assert(d == R"( push 1.000000
+ push 2.000000
+ add
+ pop
+)");
+
+ auto er{ r.mkexec() };
+
+ er.exec();
+ assert(er.result() == 3.0);
+ }
+
+ {
+ cgen::JRoutine r;
+
+ r.push(3.0);
+ r.push(4.0);
+ r.add();
+ r.push(5.0);
+ r.mul();
+ r.pop();
+
+ auto d{ cgen::disasm(r) };
+
+ p(d);
+ assert(d == R"( push 3.000000
+ push 4.000000
+ add
+ push 5.000000
+ mul
+ pop
+)");
+
+ auto er{ r.mkexec() };
+
+ er.exec();
+ assert(er.result() == 35.0);
+ }
+}
+
+void
+cgen_jitter()
+{
+ auto i{ 0 };
+ auto p = [&](const auto& s) {
+ std::cout << "# " << i << " {\n" << s << "\n# " << i << " }\n";
+ ++i;
+ };
+
+ {
+ ast::Nodes binop1{ ast::mkop(
+ ast::Op{ '+' }, ast::mknum(1), ast::mknum(2)) };
+ auto j{ cgen::jitter(binop1.begin(), binop1.end()) };
+ }
+
{
ast::Nodes ass1{ ast::mkass(
ast::Id{ "x" },
@@ -34,6 +132,7 @@ cgen_1()
p(s);
assert(s == "(setq x (+ (/ 1 2) (* 3 4)))");
}
+
{
ast::Nodes eval1{ ast::mkcall(ast::Id{ "eval" },
ast::mkstr(ast::Str{ "y = 1 + x" })) };
@@ -49,6 +148,17 @@ cgen_1()
int
main()
{
- cgen_1();
+ // To manage VM initialization/deintialization process
+ // (this is like a ScopeGuard)
+ std::unique_ptr<void, void (*)(void*)> vm_init(
+ [] {
+ toctave_initialize();
+ return reinterpret_cast<void*>(1); /* dummy */
+ }(),
+ [](void*) { toctave_finalize(); });
+
+ cgen_sexpr();
+ cgen_jroutine();
+ cgen_jitter();
return 0;
}
diff --git a/jitter.patch b/jitter.patch
@@ -0,0 +1,97 @@
+diff --git a/jitter/jitter-missing.h b/jitter/jitter-missing.h
+index 80cefdd..e84dc79 100644
+--- a/jitter/jitter-missing.h
++++ b/jitter/jitter-missing.h
+@@ -124,12 +124,12 @@
+
+ /* Do nothing. */
+ void
+-flockfile ()
++flockfile (FILE *)
+ __attribute__ ((nonnull (1)));
+
+ /* Do nothing. */
+ void
+-funlockfile ()
++funlockfile (FILE *)
+ __attribute__ ((nonnull (1)));
+
+ #endif // #ifndef JITTER_MISSING_H_
+diff --git a/templates/vm.h b/templates/vm.h
+index 6fcfbbb..c66d43b 100644
+--- a/templates/vm.h
++++ b/templates/vm.h
+@@ -1125,6 +1125,36 @@ vmprefix_program_point;
+
+
+
++/* VM exit status.
++ * ************************************************************************** */
++
++/* A value of this type is returned by a VM after execution, and the last
++ returned value is also held in the VM state in order to make consistency
++ checks. */
++enum vmprefix_exit_status
++ {
++ /* This state has never been used for execution. This is the initial value
++ within the state, and is never returned after execution. */
++ vmprefix_exit_status_never_executed = 0,
++
++ /* The state is being used in execution right now; this is never returned by
++ the executor. It is an error (checked for) to execute code with a VM
++ state containing this exit status, which shows that there has been a
++ problem -- likely VM code was exited via longjmp, skipping the proper
++ cleanup. */
++ vmprefix_exit_status_being_executed = 1,
++
++ /* Some VM code has been executed. It is now possible to execute more code
++ (including the same code again) in the same state. */
++ vmprefix_exit_status_exited = 2,
++
++ /* Code execution has been interrupted for debugging, but can be resumed. */
++ vmprefix_exit_status_debug = 3,
++ };
++
++
++
++
+ /* Executing code from an executable routine.
+ * ************************************************************************** */
+
+@@ -1185,36 +1215,6 @@ vmprefix_execute_routine (jitter_routine r,
+ __attribute__ ((nonnull (1, 2)));
+
+
+-
+-
+-/* VM exit status.
+- * ************************************************************************** */
+-
+-/* A value of this type is returned by a VM after execution, and the last
+- returned value is also held in the VM state in order to make consistency
+- checks. */
+-enum vmprefix_exit_status
+- {
+- /* This state has never been used for execution. This is the initial value
+- within the state, and is never returned after execution. */
+- vmprefix_exit_status_never_executed = 0,
+-
+- /* The state is being used in execution right now; this is never returned by
+- the executor. It is an error (checked for) to execute code with a VM
+- state containing this exit status, which shows that there has been a
+- problem -- likely VM code was exited via longjmp, skipping the proper
+- cleanup. */
+- vmprefix_exit_status_being_executed = 1,
+-
+- /* Some VM code has been executed. It is now possible to execute more code
+- (including the same code again) in the same state. */
+- vmprefix_exit_status_exited = 2,
+-
+- /* Code execution has been interrupted for debugging, but can be resumed. */
+- vmprefix_exit_status_debug = 3,
+- };
+-
+-
+
+
+ /* Low-level debugging features relying on assembly: data locations.
diff --git a/toctave.jitter b/toctave.jitter
@@ -0,0 +1,136 @@
+
+vm
+ set prefix "toctave"
+end
+
+stack s
+ long-name "mainstack"
+ c-element-type "double"
+ c-initial-value "0.0"
+ element-no 4096
+ guard-underflow
+ guard-overflow
+ tos-optimized
+end
+
+wrapped-functions
+ pow
+ memcpy
+ toctave_result
+end
+
+state-struct-runtime-c
+ code
+ double result;
+
+ jitter_program_point point;
+ int status;
+ end
+end
+
+state-initialization-c
+ code
+ jitter_state_runtime->result = 0.0; // maybe NaN is better
+ jitter_state_runtime->point = NULL;
+ jitter_state_runtime->status = -1;
+ end
+end
+
+early-header-c
+ code
+#include <math.h>
+#include <stdlib.h>
+ end
+end
+
+printer-c
+ code
+
+// Jitter uses this function to print literal values in instructions (like
+// push instruction)
+static void
+double_literal_printer(jitter_print_context ctx, uintptr_t n)
+{
+ double d;
+
+ memcpy(&d, &n, sizeof(n));
+ jitter_print_double(ctx, d);
+}
+
+ end
+end
+
+# Stack manipulation
+
+instruction push (?n double_literal_printer)
+ code
+ uintptr_t n = JITTER_ARGN0;
+ double d;
+
+ memcpy(&d, &n, sizeof(n));
+ TOCTAVE_PUSH_MAINSTACK(d);
+ end
+end
+
+instruction pop ()
+ code
+ TOCTAVE_STATE_RUNTIME_FIELD (result) = TOCTAVE_TOP_MAINSTACK();
+ TOCTAVE_DROP_MAINSTACK();
+ end
+end
+
+instruction drop ()
+ code
+ TOCTAVE_DROP_MAINSTACK();
+ end
+end
+
+# Arithmetic
+
+# Stack: (a b -- a^b)
+instruction pow ()
+ code
+ TOCTAVE_TOP_MAINSTACK() =
+ pow(/* a */ TOCTAVE_UNDER_TOP_MAINSTACK(),
+ /* b */ TOCTAVE_TOP_MAINSTACK()); /* Stack: (a a^b) */
+ TOCTAVE_NIP_MAINSTACK(); /* Stack: (a^b) */
+ end
+end
+
+# Stack: (a b -- a*b)
+instruction mul ()
+ code
+ TOCTAVE_TOP_MAINSTACK() =
+ /* a */ TOCTAVE_UNDER_TOP_MAINSTACK() *
+ /* b */ TOCTAVE_TOP_MAINSTACK(); /* Stack: (a a*b) */
+ TOCTAVE_NIP_MAINSTACK(); /* Stack: (a*b) */
+ end
+end
+
+# Stack: (a b -- a/b)
+instruction div ()
+ non-relocatable
+ code
+ TOCTAVE_TOP_MAINSTACK() =
+ /* a */ TOCTAVE_UNDER_TOP_MAINSTACK() /
+ /* b */ TOCTAVE_TOP_MAINSTACK(); /* Stack: (a a*b) */
+ end
+end
+
+# Stack: (a b -- a+b)
+instruction add ()
+ code
+ TOCTAVE_TOP_MAINSTACK() =
+ /* a */ TOCTAVE_UNDER_TOP_MAINSTACK() +
+ /* b */ TOCTAVE_TOP_MAINSTACK(); /* Stack: (a a*b) */
+ end
+end
+
+# Stack: (a b -- a-b)
+instruction sub ()
+ code
+ TOCTAVE_TOP_MAINSTACK() =
+ /* a */ TOCTAVE_UNDER_TOP_MAINSTACK() -
+ /* b */ TOCTAVE_TOP_MAINSTACK(); /* Stack: (a a*b) */
+ end
+end