diff --git a/crypto/vm/continuation.cpp b/crypto/vm/continuation.cpp index 91386980..bc67c6d2 100644 --- a/crypto/vm/continuation.cpp +++ b/crypto/vm/continuation.cpp @@ -27,8 +27,8 @@ namespace vm { -int Continuation::jump_w(VmState* st) & { - return static_cast(this)->jump(st); +td::Ref Continuation::jump_w(VmState* st, int& exitcode) & { + return static_cast(this)->jump(st, exitcode); } bool Continuation::has_c0() const { @@ -286,7 +286,7 @@ std::string QuitCont::type() const { return "vmc_quit"; } -int ExcQuitCont::jump(VmState* st) const & { +td::Ref ExcQuitCont::jump(VmState* st, int& exitcode) const& { int n = 0; try { n = st->get_stack().pop_smallint_range(0xffff); @@ -294,7 +294,8 @@ int ExcQuitCont::jump(VmState* st) const & { n = vme.get_errno(); } VM_LOG(st) << "default exception handler, terminating vm with exit code " << n; - return ~n; + exitcode = ~n; + return {}; } std::string ExcQuitCont::type() const { @@ -311,16 +312,16 @@ Ref ExcQuitCont::deserialize(CellSlice& cs, int mode) { return cs.fetch_ulong(4) == 9 ? Ref{true} : Ref{}; } -int PushIntCont::jump(VmState* st) const & { +td::Ref PushIntCont::jump(VmState* st, int& exitcode) const& { VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)"; st->get_stack().push_smallint(push_val); - return st->jump(next); + return next; } -int PushIntCont::jump_w(VmState* st) & { +td::Ref PushIntCont::jump_w(VmState* st, int& exitcode) & { VM_LOG(st) << "execute implicit PUSH " << push_val; st->get_stack().push_smallint(push_val); - return st->jump(std::move(next)); + return std::move(next); } std::string PushIntCont::type() const { @@ -345,20 +346,20 @@ Ref PushIntCont::deserialize(CellSlice& cs, int mode) { } } -int ArgContExt::jump(VmState* st) const & { +td::Ref ArgContExt::jump(VmState* st, int& exitcode) const& { st->adjust_cr(data.save); if (data.cp != -1) { st->force_cp(data.cp); } - return ext->jump(st); + return ext; } -int ArgContExt::jump_w(VmState* st) & { +td::Ref ArgContExt::jump_w(VmState* st, int& exitcode) & { st->adjust_cr(std::move(data.save)); if (data.cp != -1) { st->force_cp(data.cp); } - return st->jump_to(std::move(ext)); + return std::move(ext); } bool ArgContExt::serialize(CellBuilder& cb) const { @@ -382,32 +383,32 @@ std::string ArgContExt::type() const { return "vmc_envelope"; } -int RepeatCont::jump(VmState* st) const & { +td::Ref RepeatCont::jump(VmState* st, int& exitcode) const& { VM_LOG(st) << "repeat " << count << " more times (slow)\n"; if (count <= 0) { - return st->jump(after); + return after; } if (body->has_c0()) { - return st->jump(body); + return body; } st->set_c0(Ref{true, body, after, count - 1}); - return st->jump(body); + return body; } -int RepeatCont::jump_w(VmState* st) & { +td::Ref RepeatCont::jump_w(VmState* st, int& exitcode) & { VM_LOG(st) << "repeat " << count << " more times\n"; if (count <= 0) { body.clear(); - return st->jump(std::move(after)); + return std::move(after); } if (body->has_c0()) { after.clear(); - return st->jump(std::move(body)); + return std::move(body); } // optimization: since this is unique, reuse *this instead of creating new object --count; st->set_c0(Ref{this}); - return st->jump(body); + return body; } bool RepeatCont::serialize(CellBuilder& cb) const { @@ -443,21 +444,21 @@ int VmState::repeat(Ref body, Ref after, long long c } } -int AgainCont::jump(VmState* st) const & { +td::Ref AgainCont::jump(VmState* st, int& exitcode) const& { VM_LOG(st) << "again an infinite loop iteration (slow)\n"; if (!body->has_c0()) { st->set_c0(Ref{this}); } - return st->jump(body); + return body; } -int AgainCont::jump_w(VmState* st) & { +td::Ref AgainCont::jump_w(VmState* st, int& exitcode) & { VM_LOG(st) << "again an infinite loop iteration\n"; if (!body->has_c0()) { st->set_c0(Ref{this}); - return st->jump(body); + return body; } else { - return st->jump(std::move(body)); + return std::move(body); } } @@ -485,31 +486,31 @@ int VmState::again(Ref body) { return jump(Ref{true, std::move(body)}); } -int UntilCont::jump(VmState* st) const & { +td::Ref UntilCont::jump(VmState* st, int& exitcode) const& { VM_LOG(st) << "until loop body end (slow)\n"; if (st->get_stack().pop_bool()) { VM_LOG(st) << "until loop terminated\n"; - return st->jump(after); + return after; } if (!body->has_c0()) { st->set_c0(Ref{this}); } - return st->jump(body); + return body; } -int UntilCont::jump_w(VmState* st) & { +td::Ref UntilCont::jump_w(VmState* st, int& exitcode) & { VM_LOG(st) << "until loop body end\n"; if (st->get_stack().pop_bool()) { VM_LOG(st) << "until loop terminated\n"; body.clear(); - return st->jump(std::move(after)); + return std::move(after); } if (!body->has_c0()) { st->set_c0(Ref{this}); - return st->jump(body); + return body; } else { after.clear(); - return st->jump(std::move(body)); + return std::move(body); } } @@ -541,54 +542,54 @@ int VmState::until(Ref body, Ref after) { return jump(std::move(body)); } -int WhileCont::jump(VmState* st) const & { +td::Ref WhileCont::jump(VmState* st, int& exitcode) const& { if (chkcond) { VM_LOG(st) << "while loop condition end (slow)\n"; if (!st->get_stack().pop_bool()) { VM_LOG(st) << "while loop terminated\n"; - return st->jump(after); + return after; } if (!body->has_c0()) { st->set_c0(Ref{true, cond, body, after, false}); } - return st->jump(body); + return body; } else { VM_LOG(st) << "while loop body end (slow)\n"; if (!cond->has_c0()) { st->set_c0(Ref{true, cond, body, after, true}); } - return st->jump(cond); + return cond; } } -int WhileCont::jump_w(VmState* st) & { +td::Ref WhileCont::jump_w(VmState* st, int& exitcode) & { if (chkcond) { VM_LOG(st) << "while loop condition end\n"; if (!st->get_stack().pop_bool()) { VM_LOG(st) << "while loop terminated\n"; cond.clear(); body.clear(); - return st->jump(std::move(after)); + return std::move(after); } if (!body->has_c0()) { chkcond = false; // re-use current object since we hold the unique pointer to it st->set_c0(Ref{this}); - return st->jump(body); + return body; } else { cond.clear(); after.clear(); - return st->jump(std::move(body)); + return std::move(body); } } else { VM_LOG(st) << "while loop body end\n"; if (!cond->has_c0()) { chkcond = true; // re-use current object st->set_c0(Ref{this}); - return st->jump(cond); + return cond; } else { body.clear(); after.clear(); - return st->jump(std::move(cond)); + return std::move(cond); } } } @@ -627,16 +628,16 @@ int VmState::loop_while(Ref cond, Ref body, Ref OrdCont::jump(VmState* st, int& exitcode) const& { st->adjust_cr(data.save); st->set_code(code, data.cp); - return 0; + return {}; } -int OrdCont::jump_w(VmState* st) & { +td::Ref OrdCont::jump_w(VmState* st, int& exitcode) & { st->adjust_cr(std::move(data.save)); st->set_code(std::move(code), data.cp); - return 0; + return {}; } bool OrdCont::serialize(CellBuilder& cb) const { diff --git a/crypto/vm/continuation.h b/crypto/vm/continuation.h index 8208fc16..0c758c92 100644 --- a/crypto/vm/continuation.h +++ b/crypto/vm/continuation.h @@ -161,8 +161,8 @@ struct ControlData { class Continuation : public td::CntObject { public: - virtual int jump(VmState* st) const & = 0; - virtual int jump_w(VmState* st) &; + virtual td::Ref jump(VmState* st, int& exitcode) const& = 0; + virtual td::Ref jump_w(VmState* st, int& exitcode) &; virtual ControlData* get_cdata() { return 0; } @@ -203,8 +203,9 @@ class QuitCont : public Continuation { QuitCont(int _code = 0) : exit_code(_code) { } ~QuitCont() override = default; - int jump(VmState* st) const & override { - return ~exit_code; + td::Ref jump(VmState* st, int& exitcode) const& override { + exitcode = ~exit_code; + return {}; } bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); @@ -215,7 +216,7 @@ class ExcQuitCont : public Continuation { public: ExcQuitCont() = default; ~ExcQuitCont() override = default; - int jump(VmState* st) const & override; + td::Ref jump(VmState* st, int& exitcode) const& override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -229,8 +230,8 @@ class PushIntCont : public Continuation { PushIntCont(int val, Ref _next) : push_val(val), next(_next) { } ~PushIntCont() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -245,8 +246,8 @@ class RepeatCont : public Continuation { : body(std::move(_body)), after(std::move(_after)), count(_count) { } ~RepeatCont() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -259,8 +260,8 @@ class AgainCont : public Continuation { AgainCont(Ref _body) : body(std::move(_body)) { } ~AgainCont() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -273,8 +274,8 @@ class UntilCont : public Continuation { UntilCont(Ref _body, Ref _after) : body(std::move(_body)), after(std::move(_after)) { } ~UntilCont() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -289,8 +290,8 @@ class WhileCont : public Continuation { : cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) { } ~WhileCont() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; bool serialize(CellBuilder& cb) const override; static Ref deserialize(CellSlice& cs, int mode = 0); std::string type() const override; @@ -312,8 +313,8 @@ class ArgContExt : public Continuation { ArgContExt(const ArgContExt&) = default; ArgContExt(ArgContExt&&) = default; ~ArgContExt() override = default; - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; ControlData* get_cdata() override { return &data; } @@ -354,8 +355,8 @@ class OrdCont : public Continuation { td::CntObject* make_copy() const override { return new OrdCont{*this}; } - int jump(VmState* st) const & override; - int jump_w(VmState* st) & override; + td::Ref jump(VmState* st, int& exitcode) const& override; + td::Ref jump_w(VmState* st, int& exitcode) & override; ControlData* get_cdata() override { return &data; diff --git a/crypto/vm/vm.h b/crypto/vm/vm.h index e5cca026..e67d54f1 100644 --- a/crypto/vm/vm.h +++ b/crypto/vm/vm.h @@ -370,7 +370,11 @@ class VmState final : public VmStateInterface { throw VmFatal{}; } int jump_to(Ref cont) { - return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this); + int res = 0; + while (cont.not_null()) { + cont = cont->is_unique() ? cont.unique_write().jump_w(this, res) : cont->jump(this, res); + } + return res; } static Ref convert_code_cell(Ref code_cell); bool try_commit();