Skip to content

Commit b5734d2

Browse files
committed
Get rid of recursion in tvm continuations
1 parent eea95ae commit b5734d2

File tree

3 files changed

+72
-66
lines changed

3 files changed

+72
-66
lines changed

crypto/vm/continuation.cpp

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727

2828
namespace vm {
2929

30-
int Continuation::jump_w(VmState* st) & {
31-
return static_cast<const Continuation*>(this)->jump(st);
30+
td::Ref<Continuation> Continuation::jump_w(VmState* st, int& exitcode) & {
31+
return static_cast<const Continuation*>(this)->jump(st, exitcode);
3232
}
3333

3434
bool Continuation::has_c0() const {
@@ -286,15 +286,16 @@ std::string QuitCont::type() const {
286286
return "vmc_quit";
287287
}
288288

289-
int ExcQuitCont::jump(VmState* st) const & {
289+
td::Ref<Continuation> ExcQuitCont::jump(VmState* st, int& exitcode) const& {
290290
int n = 0;
291291
try {
292292
n = st->get_stack().pop_smallint_range(0xffff);
293293
} catch (const VmError& vme) {
294294
n = vme.get_errno();
295295
}
296296
VM_LOG(st) << "default exception handler, terminating vm with exit code " << n;
297-
return ~n;
297+
exitcode = ~n;
298+
return {};
298299
}
299300

300301
std::string ExcQuitCont::type() const {
@@ -311,16 +312,16 @@ Ref<ExcQuitCont> ExcQuitCont::deserialize(CellSlice& cs, int mode) {
311312
return cs.fetch_ulong(4) == 9 ? Ref<ExcQuitCont>{true} : Ref<ExcQuitCont>{};
312313
}
313314

314-
int PushIntCont::jump(VmState* st) const & {
315+
td::Ref<Continuation> PushIntCont::jump(VmState* st, int& exitcode) const& {
315316
VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)";
316317
st->get_stack().push_smallint(push_val);
317-
return st->jump(next);
318+
return next;
318319
}
319320

320-
int PushIntCont::jump_w(VmState* st) & {
321+
td::Ref<Continuation> PushIntCont::jump_w(VmState* st, int& exitcode) & {
321322
VM_LOG(st) << "execute implicit PUSH " << push_val;
322323
st->get_stack().push_smallint(push_val);
323-
return st->jump(std::move(next));
324+
return std::move(next);
324325
}
325326

326327
std::string PushIntCont::type() const {
@@ -345,20 +346,20 @@ Ref<PushIntCont> PushIntCont::deserialize(CellSlice& cs, int mode) {
345346
}
346347
}
347348

348-
int ArgContExt::jump(VmState* st) const & {
349+
td::Ref<Continuation> ArgContExt::jump(VmState* st, int& exitcode) const& {
349350
st->adjust_cr(data.save);
350351
if (data.cp != -1) {
351352
st->force_cp(data.cp);
352353
}
353-
return ext->jump(st);
354+
return ext;
354355
}
355356

356-
int ArgContExt::jump_w(VmState* st) & {
357+
td::Ref<Continuation> ArgContExt::jump_w(VmState* st, int& exitcode) & {
357358
st->adjust_cr(std::move(data.save));
358359
if (data.cp != -1) {
359360
st->force_cp(data.cp);
360361
}
361-
return st->jump_to(std::move(ext));
362+
return std::move(ext);
362363
}
363364

364365
bool ArgContExt::serialize(CellBuilder& cb) const {
@@ -382,32 +383,32 @@ std::string ArgContExt::type() const {
382383
return "vmc_envelope";
383384
}
384385

385-
int RepeatCont::jump(VmState* st) const & {
386+
td::Ref<Continuation> RepeatCont::jump(VmState* st, int& exitcode) const& {
386387
VM_LOG(st) << "repeat " << count << " more times (slow)\n";
387388
if (count <= 0) {
388-
return st->jump(after);
389+
return after;
389390
}
390391
if (body->has_c0()) {
391-
return st->jump(body);
392+
return body;
392393
}
393394
st->set_c0(Ref<RepeatCont>{true, body, after, count - 1});
394-
return st->jump(body);
395+
return body;
395396
}
396397

397-
int RepeatCont::jump_w(VmState* st) & {
398+
td::Ref<Continuation> RepeatCont::jump_w(VmState* st, int& exitcode) & {
398399
VM_LOG(st) << "repeat " << count << " more times\n";
399400
if (count <= 0) {
400401
body.clear();
401-
return st->jump(std::move(after));
402+
return std::move(after);
402403
}
403404
if (body->has_c0()) {
404405
after.clear();
405-
return st->jump(std::move(body));
406+
return std::move(body);
406407
}
407408
// optimization: since this is unique, reuse *this instead of creating new object
408409
--count;
409410
st->set_c0(Ref<RepeatCont>{this});
410-
return st->jump(body);
411+
return body;
411412
}
412413

413414
bool RepeatCont::serialize(CellBuilder& cb) const {
@@ -443,21 +444,21 @@ int VmState::repeat(Ref<Continuation> body, Ref<Continuation> after, long long c
443444
}
444445
}
445446

446-
int AgainCont::jump(VmState* st) const & {
447+
td::Ref<Continuation> AgainCont::jump(VmState* st, int& exitcode) const& {
447448
VM_LOG(st) << "again an infinite loop iteration (slow)\n";
448449
if (!body->has_c0()) {
449450
st->set_c0(Ref<AgainCont>{this});
450451
}
451-
return st->jump(body);
452+
return body;
452453
}
453454

454-
int AgainCont::jump_w(VmState* st) & {
455+
td::Ref<Continuation> AgainCont::jump_w(VmState* st, int& exitcode) & {
455456
VM_LOG(st) << "again an infinite loop iteration\n";
456457
if (!body->has_c0()) {
457458
st->set_c0(Ref<AgainCont>{this});
458-
return st->jump(body);
459+
return body;
459460
} else {
460-
return st->jump(std::move(body));
461+
return std::move(body);
461462
}
462463
}
463464

@@ -485,31 +486,31 @@ int VmState::again(Ref<Continuation> body) {
485486
return jump(Ref<AgainCont>{true, std::move(body)});
486487
}
487488

488-
int UntilCont::jump(VmState* st) const & {
489+
td::Ref<Continuation> UntilCont::jump(VmState* st, int& exitcode) const& {
489490
VM_LOG(st) << "until loop body end (slow)\n";
490491
if (st->get_stack().pop_bool()) {
491492
VM_LOG(st) << "until loop terminated\n";
492-
return st->jump(after);
493+
return after;
493494
}
494495
if (!body->has_c0()) {
495496
st->set_c0(Ref<UntilCont>{this});
496497
}
497-
return st->jump(body);
498+
return body;
498499
}
499500

500-
int UntilCont::jump_w(VmState* st) & {
501+
td::Ref<Continuation> UntilCont::jump_w(VmState* st, int& exitcode) & {
501502
VM_LOG(st) << "until loop body end\n";
502503
if (st->get_stack().pop_bool()) {
503504
VM_LOG(st) << "until loop terminated\n";
504505
body.clear();
505-
return st->jump(std::move(after));
506+
return std::move(after);
506507
}
507508
if (!body->has_c0()) {
508509
st->set_c0(Ref<UntilCont>{this});
509-
return st->jump(body);
510+
return body;
510511
} else {
511512
after.clear();
512-
return st->jump(std::move(body));
513+
return std::move(body);
513514
}
514515
}
515516

@@ -541,54 +542,54 @@ int VmState::until(Ref<Continuation> body, Ref<Continuation> after) {
541542
return jump(std::move(body));
542543
}
543544

544-
int WhileCont::jump(VmState* st) const & {
545+
td::Ref<Continuation> WhileCont::jump(VmState* st, int& exitcode) const& {
545546
if (chkcond) {
546547
VM_LOG(st) << "while loop condition end (slow)\n";
547548
if (!st->get_stack().pop_bool()) {
548549
VM_LOG(st) << "while loop terminated\n";
549-
return st->jump(after);
550+
return after;
550551
}
551552
if (!body->has_c0()) {
552553
st->set_c0(Ref<WhileCont>{true, cond, body, after, false});
553554
}
554-
return st->jump(body);
555+
return body;
555556
} else {
556557
VM_LOG(st) << "while loop body end (slow)\n";
557558
if (!cond->has_c0()) {
558559
st->set_c0(Ref<WhileCont>{true, cond, body, after, true});
559560
}
560-
return st->jump(cond);
561+
return cond;
561562
}
562563
}
563564

564-
int WhileCont::jump_w(VmState* st) & {
565+
td::Ref<Continuation> WhileCont::jump_w(VmState* st, int& exitcode) & {
565566
if (chkcond) {
566567
VM_LOG(st) << "while loop condition end\n";
567568
if (!st->get_stack().pop_bool()) {
568569
VM_LOG(st) << "while loop terminated\n";
569570
cond.clear();
570571
body.clear();
571-
return st->jump(std::move(after));
572+
return std::move(after);
572573
}
573574
if (!body->has_c0()) {
574575
chkcond = false; // re-use current object since we hold the unique pointer to it
575576
st->set_c0(Ref<WhileCont>{this});
576-
return st->jump(body);
577+
return body;
577578
} else {
578579
cond.clear();
579580
after.clear();
580-
return st->jump(std::move(body));
581+
return std::move(body);
581582
}
582583
} else {
583584
VM_LOG(st) << "while loop body end\n";
584585
if (!cond->has_c0()) {
585586
chkcond = true; // re-use current object
586587
st->set_c0(Ref<WhileCont>{this});
587-
return st->jump(cond);
588+
return cond;
588589
} else {
589590
body.clear();
590591
after.clear();
591-
return st->jump(std::move(cond));
592+
return std::move(cond);
592593
}
593594
}
594595
}
@@ -627,16 +628,16 @@ int VmState::loop_while(Ref<Continuation> cond, Ref<Continuation> body, Ref<Cont
627628
return jump(std::move(cond));
628629
}
629630

630-
int OrdCont::jump(VmState* st) const & {
631+
td::Ref<Continuation> OrdCont::jump(VmState* st, int& exitcode) const& {
631632
st->adjust_cr(data.save);
632633
st->set_code(code, data.cp);
633-
return 0;
634+
return {};
634635
}
635636

636-
int OrdCont::jump_w(VmState* st) & {
637+
td::Ref<Continuation> OrdCont::jump_w(VmState* st, int& exitcode) & {
637638
st->adjust_cr(std::move(data.save));
638639
st->set_code(std::move(code), data.cp);
639-
return 0;
640+
return {};
640641
}
641642

642643
bool OrdCont::serialize(CellBuilder& cb) const {

crypto/vm/continuation.h

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ struct ControlData {
161161

162162
class Continuation : public td::CntObject {
163163
public:
164-
virtual int jump(VmState* st) const & = 0;
165-
virtual int jump_w(VmState* st) &;
164+
virtual td::Ref<Continuation> jump(VmState* st, int& exitcode) const& = 0;
165+
virtual td::Ref<Continuation> jump_w(VmState* st, int& exitcode) &;
166166
virtual ControlData* get_cdata() {
167167
return 0;
168168
}
@@ -203,8 +203,9 @@ class QuitCont : public Continuation {
203203
QuitCont(int _code = 0) : exit_code(_code) {
204204
}
205205
~QuitCont() override = default;
206-
int jump(VmState* st) const & override {
207-
return ~exit_code;
206+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override {
207+
exitcode = ~exit_code;
208+
return {};
208209
}
209210
bool serialize(CellBuilder& cb) const override;
210211
static Ref<QuitCont> deserialize(CellSlice& cs, int mode = 0);
@@ -215,7 +216,7 @@ class ExcQuitCont : public Continuation {
215216
public:
216217
ExcQuitCont() = default;
217218
~ExcQuitCont() override = default;
218-
int jump(VmState* st) const & override;
219+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
219220
bool serialize(CellBuilder& cb) const override;
220221
static Ref<ExcQuitCont> deserialize(CellSlice& cs, int mode = 0);
221222
std::string type() const override;
@@ -229,8 +230,8 @@ class PushIntCont : public Continuation {
229230
PushIntCont(int val, Ref<Continuation> _next) : push_val(val), next(_next) {
230231
}
231232
~PushIntCont() override = default;
232-
int jump(VmState* st) const & override;
233-
int jump_w(VmState* st) & override;
233+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
234+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
234235
bool serialize(CellBuilder& cb) const override;
235236
static Ref<PushIntCont> deserialize(CellSlice& cs, int mode = 0);
236237
std::string type() const override;
@@ -245,8 +246,8 @@ class RepeatCont : public Continuation {
245246
: body(std::move(_body)), after(std::move(_after)), count(_count) {
246247
}
247248
~RepeatCont() override = default;
248-
int jump(VmState* st) const & override;
249-
int jump_w(VmState* st) & override;
249+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
250+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
250251
bool serialize(CellBuilder& cb) const override;
251252
static Ref<RepeatCont> deserialize(CellSlice& cs, int mode = 0);
252253
std::string type() const override;
@@ -259,8 +260,8 @@ class AgainCont : public Continuation {
259260
AgainCont(Ref<Continuation> _body) : body(std::move(_body)) {
260261
}
261262
~AgainCont() override = default;
262-
int jump(VmState* st) const & override;
263-
int jump_w(VmState* st) & override;
263+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
264+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
264265
bool serialize(CellBuilder& cb) const override;
265266
static Ref<AgainCont> deserialize(CellSlice& cs, int mode = 0);
266267
std::string type() const override;
@@ -273,8 +274,8 @@ class UntilCont : public Continuation {
273274
UntilCont(Ref<Continuation> _body, Ref<Continuation> _after) : body(std::move(_body)), after(std::move(_after)) {
274275
}
275276
~UntilCont() override = default;
276-
int jump(VmState* st) const & override;
277-
int jump_w(VmState* st) & override;
277+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
278+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
278279
bool serialize(CellBuilder& cb) const override;
279280
static Ref<UntilCont> deserialize(CellSlice& cs, int mode = 0);
280281
std::string type() const override;
@@ -289,8 +290,8 @@ class WhileCont : public Continuation {
289290
: cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) {
290291
}
291292
~WhileCont() override = default;
292-
int jump(VmState* st) const & override;
293-
int jump_w(VmState* st) & override;
293+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
294+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
294295
bool serialize(CellBuilder& cb) const override;
295296
static Ref<WhileCont> deserialize(CellSlice& cs, int mode = 0);
296297
std::string type() const override;
@@ -312,8 +313,8 @@ class ArgContExt : public Continuation {
312313
ArgContExt(const ArgContExt&) = default;
313314
ArgContExt(ArgContExt&&) = default;
314315
~ArgContExt() override = default;
315-
int jump(VmState* st) const & override;
316-
int jump_w(VmState* st) & override;
316+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
317+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
317318
ControlData* get_cdata() override {
318319
return &data;
319320
}
@@ -354,8 +355,8 @@ class OrdCont : public Continuation {
354355
td::CntObject* make_copy() const override {
355356
return new OrdCont{*this};
356357
}
357-
int jump(VmState* st) const & override;
358-
int jump_w(VmState* st) & override;
358+
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
359+
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
359360

360361
ControlData* get_cdata() override {
361362
return &data;

crypto/vm/vm.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,11 @@ class VmState final : public VmStateInterface {
370370
throw VmFatal{};
371371
}
372372
int jump_to(Ref<Continuation> cont) {
373-
return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this);
373+
int res = 0;
374+
while (cont.not_null()) {
375+
cont = cont->is_unique() ? cont.unique_write().jump_w(this, res) : cont->jump(this, res);
376+
}
377+
return res;
374378
}
375379
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
376380
bool try_commit();

0 commit comments

Comments
 (0)