#include "CrossLang.hpp" // THANKS TO https://www.youtube.com/watch?v=R-z2Hv-7nxk namespace Tesses::CrossLang { TTask::TTask(std::shared_ptr gc) { this->gc = gc; } TTask *TTask::Create(GCList &ls) { TTask *task = new TTask(ls.GetGC()); ls.Add(task); task->gc->Watch(task); return task; } bool TTask::IsCompleted() { gc->BarrierBegin(); bool r = this->isCompleted; gc->BarrierEnd(); return r; } TTask *TTask::ContinueWith(GCList &ls, TCallable *callable) { TTask *task = TTask::Create(ls); TExternalMethod *em = TExternalMethod::Create( ls, "Internal async thing", {"_asyncObj"}, [callable, task](GCList &ls, std::vector args) -> TObject { try { task->SetSucceeded(callable->Call(ls, args)); } catch (...) { task->SetFailed(std::current_exception()); } return nullptr; }); em->watch = {callable, task}; this->gc->BarrierBegin(); if (this->isCompleted) { this->gc->BarrierEnd(); std::shared_ptr ls = std::make_shared(gc); auto cobj = this->obj; ls->Add(cobj); ls->Add(em); this->gc->GetPool()->Schedule( [ls, em, cobj](size_t s) -> void { em->Call(*ls, {cobj}); }); return task; } else { this->cont = em; } this->gc->BarrierEnd(); return task; } void TTask::ContinueWith(TCallable *callable) { this->gc->BarrierBegin(); if (this->isCompleted) { this->gc->BarrierEnd(); std::shared_ptr ls = std::make_shared(gc); auto cobj = this->obj; ls->Add(cobj); ls->Add(callable); this->gc->GetPool()->Schedule([ls, callable, cobj](size_t s) -> void { callable->Call(*ls, {cobj}); }); return; } else { this->cont = callable; } this->gc->BarrierEnd(); } void TTask::SetFailed(std::exception_ptr ex) { this->ex = ex; this->SetSucceeded(nullptr); } void TTask::SetSucceeded(TObject v) { gc->BarrierBegin(); if (this->isCompleted) { gc->BarrierEnd(); return; } this->isCompleted = true; this->obj = v; auto cont = this->cont; gc->BarrierEnd(); if (cont != nullptr) { std::shared_ptr ls = std::make_shared(gc); auto callable = cont; ls->Add(v); ls->Add(callable); this->gc->GetPool()->Schedule( [ls, callable, v](size_t s) -> void { callable->Call(*ls, {v}); }); } } TObject TTask::Wait() { while (true) { gc->BarrierBegin(); if (this->isCompleted) { if (this->ex) { auto error = this->ex; gc->BarrierEnd(); std::rethrow_exception(error); } auto o = this->obj; gc->BarrierEnd(); return o; } gc->BarrierEnd(); } } void TTask::Mark() { if (this->marked) return; this->marked = true; GC::Mark(this->obj); if (this->cont != nullptr) this->cont->Mark(); } TTask *TTask::Run(GCList &ls, TCallable *callable) { TTask *task = TTask::Create(ls); std::shared_ptr ls2 = std::make_shared(ls.GetGC()); ls2->Add(callable); ls2->Add(task); ls.GetGC()->GetPool()->Schedule([ls2, callable, task](size_t s) -> void { try { task->SetSucceeded(callable->Call(*ls2, {})); } catch (...) { task->SetFailed(std::current_exception()); } }); return task; } TTask *TTask::FromResult(GCList &ls, TObject v) { TTask *task = TTask::Create(ls); task->SetSucceeded(v); return task; } class TTaskCseObj { std::shared_ptr gc; TTask *task; public: TTaskCseObj(std::shared_ptr gc, TTask *task) { this->gc = gc; this->task = task; } void Invoke(std::shared_ptr shared_o, CallStackEntry *cse, TObject o) { try { GCList ls(gc); cse->Push(gc, o); auto res = cse->Resume(ls); CallStackEntry *cse2; if (GetObjectHeap(res, cse2)) { auto taskPiece = cse2->Pop(ls); TTask *task; if (GetObjectHeap(taskPiece, task)) { auto em = TExternalMethod::Create( ls, "", {"obj"}, [cse2, task, shared_o]( GCList &ls, std::vector args) -> TObject { shared_o->Invoke(shared_o, cse2, args.empty() ? (TObject)Undefined() : args[0]); return nullptr; }); em->watch.push_back(task); em->watch.push_back(cse2); task->ContinueWith(em); } } else { this->task->SetSucceeded(res); } } catch (...) { this->task->SetFailed(std::current_exception()); } } }; TTask *TTask::FromClosure(GCList &ls, TClosure *closure) { auto res = closure->Call(ls, {}); CallStackEntry *ent; if (GetObjectHeap(res, ent)) { return FromCallStackEntry(ls, ent); } return FromResult(ls, res); } TTask *TTask::FromCallStackEntry(GCList &ls, CallStackEntry *ent) { TTask *task = TTask::Create(ls); // try { GCList ls2(ls.GetGC()); std::shared_ptr gc = ls.GetGC(); std::shared_ptr obj = std::make_shared(gc, task); ls2.Add(task); auto res = ent->Pop(ls2); TTask *task2; if (GetObjectHeap(res, task2)) { auto em = TExternalMethod::Create( ls2, "", {}, [ent, task, obj](GCList &ls, std::vector args) -> TObject { obj->Invoke(obj, ent, args.empty() ? (TObject)Undefined() : args[0]); return nullptr; }); em->watch.push_back(task); em->watch.push_back(ent); task2->ContinueWith(em); } /*} catch(...) { task->SetFailed(std::current_exception()); }*/ return task; } } // namespace Tesses::CrossLang