Replace time-based GC with allocation-count trigger, migrate all Create factories to GCList::Create(), fix VFSPath root path, reorder TObject variant

This commit is contained in:
2026-09-01 05:15:43 -05:00
parent 56b74dc6fc
commit 2430b62232
38 changed files with 888 additions and 806 deletions
+2 -2
View File
@@ -1490,12 +1490,12 @@ bool InterperterThread::ExecuteMethod2(std::shared_ptr<GC> gc, TObject instance,
pattern,
callable->ToRouteServerRequestHandler(gc));
}
} else if (key == "Trace") {
} else if (key == "Query") {
std::string pattern;
TCallable *callable;
if (GetArgument(args, 0, pattern) &&
GetArgumentHeap(args, 1, callable)) {
routable->Trace(
routable->Query(
pattern,
callable->ToRouteServerRequestHandler(gc));
}
+4 -4
View File
@@ -58,13 +58,13 @@ void ThrowFatalError(std::exception &ex) {
error.WriteLine(text);
}
exit(1);
std::exit(1);
}
if (clrtexcept != nullptr) {
error.WriteLine("CrossLang has encountered a fatal runtime exception");
error.WriteLine();
error.WriteLine(clrtexcept->what());
exit(1);
std::exit(1);
}
if (compiler != nullptr) {
error.WriteLine("CrossLang has encountered a compiler error");
@@ -81,13 +81,13 @@ void ThrowFatalError(std::exception &ex) {
error.Write(":");
error.WriteLine((int64_t)li.offset);
exit(1);
std::exit(1);
}
error.WriteLine("CrossLang has encountered a fatal C++ exception");
error.WriteLine();
error.Write("what(): ");
error.WriteLine(ex2->what());
exit(1);
std::exit(1);
}
} // namespace Tesses::CrossLang
+4 -30
View File
@@ -5,22 +5,8 @@
#include <iostream>
namespace Tesses::CrossLang {
TFile *TFile::Create(GCList &ls) {
TFile *f = new TFile();
f->icon = -1;
std::shared_ptr<GC> _gc = ls.GetGC();
ls.Add(f);
_gc->Watch(f);
return f;
}
TFile *TFile::Create(GCList *ls) {
TFile *f = new TFile();
f->icon = -1;
std::shared_ptr<GC> _gc = ls->GetGC();
ls->Add(f);
_gc->Watch(f);
return f;
}
TFile *TFile::Create(GCList &ls) { return ls.Create<TFile>(); }
TFile *TFile::Create(GCList *ls) { return ls->Create<TFile>(); }
void TFileChunk::Mark() {
if (this->marked)
return;
@@ -28,20 +14,8 @@ void TFileChunk::Mark() {
this->file->Mark();
}
TFileChunk *TFileChunk::Create(GCList &ls) {
TFileChunk *chk = new TFileChunk();
std::shared_ptr<GC> _gc = ls.GetGC();
ls.Add(chk);
_gc->Watch(chk);
return chk;
}
TFileChunk *TFileChunk::Create(GCList *ls) {
TFileChunk *chk = new TFileChunk();
std::shared_ptr<GC> _gc = ls->GetGC();
ls->Add(chk);
_gc->Watch(chk);
return chk;
}
TFileChunk *TFileChunk::Create(GCList &ls) { return ls.Create<TFileChunk>(); }
TFileChunk *TFileChunk::Create(GCList *ls) { return ls->Create<TFileChunk>(); }
void TFile::Mark() {
if (this->marked)
return;
+87 -79
View File
@@ -11,7 +11,18 @@
using namespace Tesses::Framework::Threading;
using namespace std::chrono;
namespace Tesses::CrossLang {
#if defined(GEKKO) || defined(_EE)
struct PthreadCmp {
bool operator()(const pthread_t &a, const pthread_t &b) const {
return pthread_equal(a, b) != 0;
}
};
static std::map<pthread_t, CallStackEntry *, PthreadCmp> current_funcs;
static Tesses::Framework::Threading::Mutex current_funcs_mtx;
#else
thread_local CallStackEntry *current_function;
#endif
bool GC::IsRunning() {
bool run = this->running;
@@ -74,7 +85,14 @@ TDictionary *CreateThread(GCList &ls, TCallable *callable, bool detached) {
TObject cb = th->callable->Call(ls, {});
gc->BarrierBegin();
th->returnValue = cb;
std::map<pthread_t, int> mt;
#if defined(GEKKO) || defined(_EE)
current_funcs_mtx.Lock();
current_funcs.erase(pthread_self());
current_funcs_mtx.Unlock();
#endif
gc->BarrierEnd();
th->hasReturned = true;
});
while (!th->hasInit)
@@ -93,50 +111,47 @@ void GC::Start() {
return new Tesses::Framework::Threading::ThreadPool(threads);
},
[](Tesses::Framework::Threading::ThreadPool *p) -> void { delete p; });
this->mtx = new Mutex();
this->running = true;
this->thrd = new Thread([this]() -> void {
std::chrono::time_point<std::chrono::system_clock> last_frame,
this_frame;
this_frame = system_clock::now();
last_frame = this_frame;
while (this->IsRunning()) {
this_frame = system_clock::now();
if ((this_frame - last_frame) > 10s) {
this->BarrierBegin();
while (this->allocs < ALLOC_THRESHOLD)
this->cond.Wait(
&this->mtx); // your wrapper around pthread_cond_wait
this->allocs = 0;
std::vector<THeapObject *> to_delete;
this->Collect(to_delete);
this->BarrierEnd();
last_frame = this_frame;
this->Collect();
}
for (auto o : to_delete)
delete o;
}
{
std::vector<THeapObject *> to_delete;
this->BarrierBegin();
this->Collect(to_delete);
this->BarrierEnd();
#if defined(_WIN32)
Sleep(100);
#else
usleep(100000);
#endif
for (auto item : to_delete)
delete item;
}
GC::Collect();
});
}
bool GC::UsingNullThreads() { return false; }
void GC::BarrierBegin() { this->mtx->Lock(); }
void GC::BarrierEnd() { this->mtx->Unlock(); }
void GC::BarrierBegin() { this->mtx.Lock(); }
void GC::BarrierEnd() { this->mtx.Unlock(); }
void GC::Watch(TObject obj) {
if (std::holds_alternative<THeapObjectHolder>(obj)) {
auto _item = std::get<THeapObjectHolder>(obj).obj;
this->BarrierBegin();
for (auto item : this->objects) {
if (item == _item) {
this->BarrierEnd();
return;
}
}
this->objects.push_back(_item);
this->objects.insert(_item);
auto nowAllocs = ++this->allocs;
this->BarrierEnd();
if (nowAllocs >= ALLOC_THRESHOLD)
this->cond.Signal();
}
}
void GC::Mark(TObject obj) {
@@ -149,65 +164,36 @@ void GC::Unwatch(TObject obj) {
if (std::holds_alternative<THeapObjectHolder>(obj)) {
auto _item = std::get<THeapObjectHolder>(obj).obj;
this->BarrierBegin();
for (auto index = this->objects.begin();
index != this->objects.end();) {
if (*index == _item) {
index = this->objects.erase(index);
continue;
}
index++;
}
this->objects.erase(_item);
this->BarrierEnd();
}
}
void GC::SetRoot(TObject obj) {
if (std::holds_alternative<THeapObjectHolder>(obj)) {
auto _item = std::get<THeapObjectHolder>(obj).obj;
this->BarrierBegin();
void GC::SetRoot(GCList *_item) {
if (_item == nullptr)
return;
this->BarrierBegin();
for (auto item : this->roots) {
if (item == _item) {
this->BarrierEnd();
return;
}
}
this->roots.push_back(_item);
this->BarrierEnd();
}
this->roots.insert(_item);
this->BarrierEnd();
}
Tesses::Framework::Threading::ThreadPool *GC::GetPool() {
return this->tpool->GetValue();
}
void GC::UnsetRoot(TObject obj) {
if (std::holds_alternative<THeapObjectHolder>(obj)) {
auto _item = std::get<THeapObjectHolder>(obj).obj;
this->BarrierBegin();
for (auto index = this->roots.begin(); index != this->roots.end();) {
if (*index == _item) {
index = this->roots.erase(index);
continue;
}
index++;
}
this->BarrierEnd();
}
void GC::UnsetRoot(GCList *_item) {
if (_item == nullptr)
return;
this->BarrierBegin();
this->roots.erase(_item);
this->BarrierEnd();
}
GC::~GC() {
GC::BarrierBegin();
this->roots.clear();
GC::BarrierEnd();
this->running = false;
this->cond.Signal();
this->thrd->Join();
delete this->thrd;
for (auto item : objects)
delete item;
delete this->tpool;
delete this->mtx;
}
void GC::RegisterEverythingCallback(
@@ -218,23 +204,45 @@ void GC::RegisterEverything(TRootEnvironment *env) {
for (auto item : this->register_everything)
item(this->shared_from_this(), env);
}
void GC::Collect() {
this->BarrierBegin();
CallStackEntry *GC::GetCurrentFunction() {
#if defined(GEKKO) || defined(_EE)
current_funcs_mtx.Lock();
auto val = current_funcs[pthread_self()];
current_funcs_mtx.Unlock();
return val;
#else
return current_function;
#endif
}
void GC::SetCurrentFunction(CallStackEntry *cse) {
#if defined(GEKKO) || defined(_EE)
current_funcs_mtx.Lock();
current_funcs[pthread_self()] = cse;
current_funcs_mtx.Unlock();
#else
current_function = cse;
#endif
}
void GC::Collect(std::vector<THeapObject *> &to_delete) {
for (auto item : this->objects) {
item->marked = false;
}
for (auto item : this->roots) {
item->Mark();
}
for (auto index = this->objects.begin(); index != this->objects.end();
index++) {
for (auto index = this->objects.begin(); index != this->objects.end();) {
THeapObject *o = *index;
if (!o->marked) {
delete o;
this->objects.erase(index);
index--;
to_delete.push_back(o);
index = this->objects.erase(index);
} else {
++index;
}
}
this->BarrierEnd();
}
}; // namespace Tesses::CrossLang
+1 -2
View File
@@ -8,7 +8,7 @@ GCList::GCList(std::shared_ptr<GC> gc) {
gc->BarrierEnd();
}
std::shared_ptr<GC> GCList::GetGC() { return this->gc; }
std::shared_ptr<GC> GCList::GetGC() const { return this->gc; }
void GCList::Remove(TObject obj) {
if (std::holds_alternative<THeapObjectHolder>(obj)) {
auto _item = std::get<THeapObjectHolder>(obj).obj;
@@ -40,7 +40,6 @@ void GCList::Add(TObject obj) {
}
}
void GCList::Mark() {
this->marked = true;
for (auto item : this->items) {
item->Mark();
}
+69 -55
View File
@@ -12,8 +12,6 @@
namespace Tesses::CrossLang {
thread_local CallStackEntry *current_function = nullptr;
TObject ExecuteFunction(GCList &ls, TCallable *callable,
std::vector<TObject> args) {
return callable->Call(ls, args);
@@ -2113,8 +2111,14 @@ bool InterperterThread::Throw(std::shared_ptr<GC> gc) {
if (!std::holds_alternative<Undefined>(_res2)) {
auto env = cse.back()->env;
if (!env->GetRootEnvironment()->HandleException(gc, env, _res2))
if (!env->GetRootEnvironment()->HandleException(gc, env, _res2)) {
TNativeException *nex;
if (GetObjectHeap(_res2, nex)) {
nex->ThrowIt();
}
throw VMByteCodeException(gc, _res2, cse.back());
}
}
return false;
}
@@ -2223,6 +2227,7 @@ bool InterperterThread::JumpUndefined(std::shared_ptr<GC> gc) {
bool InterperterThread::Jump(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
if (stk->ip + 4 <= stk->callable->closure->code.size()) {
@@ -2409,23 +2414,39 @@ bool InterperterThread::TryCatch(std::shared_ptr<GC> gc) {
if (GetObjectHeap(tryFn, tryC) && GetObjectHeap(catchFn, catchC)) {
try {
stk->Push(gc, tryC->Call(ls, {}));
}
catch (std::exception &ex) {
TDictionary *dict = TDictionary::Create(ls);
auto gc = ls.GetGC();
auto myEx = dynamic_cast<VMByteCodeException *>(&ex);
if (myEx != nullptr) {
stk->Push(gc, catchC->Call(ls, {myEx->exception}));
} else {
gc->BarrierBegin();
} catch (std::bad_alloc &ex) {
std::cerr
<< "CrossLang has failed to allocate, sorry for termination."
<< std::endl;
std::exit(1);
} catch (const std::string &ex) {
stk->Push(gc, catchC->Call(ls, {ex}));
} catch (const char *ex) {
dict->SetValue("Type", "NativeException");
dict->SetValue("Text", ex.what());
gc->BarrierEnd();
stk->Push(gc,
catchC->Call(ls, {std::string{ex != nullptr ? ex : ""}}));
} catch (std::runtime_error &ex) {
stk->Push(gc, catchC->Call(ls, {dict}));
}
stk->Push(
gc, catchC->Call(ls, {TNativeObject::Create<TException>(
ls, ex.what(), "RuntimeException")}));
} catch (VMException &ex) {
stk->Push(
gc, catchC->Call(ls, {TNativeObject::Create<TException>(
ls, ex.GetMessage(), "VMException")}));
} catch (VMByteCodeException &ex) {
stk->Push(gc, catchC->Call(ls, {ex.exception}));
} catch (std::exception &ex) {
stk->Push(gc,
catchC->Call(
ls, {TNativeObject::Create<TNativeException>(
ls, ex.what(), std::current_exception())}));
} catch (...) {
stk->Push(gc,
catchC->Call(ls, {TNativeObject::Create<TNativeException>(
ls, "<No Message>",
std::current_exception())}));
}
}
return false;
@@ -2693,14 +2714,14 @@ void InterperterThread::Execute(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
#define VM_OPCODE_TABLE_INLINE
#include "vm_opcode_table.h"
#include "vm_opcode_table.def"
#undef VM_OPCODE_TABLE_INLINE
execute:
if (!cse.empty()) {
auto stk = cse.back();
current_function = stk;
GC::SetCurrentFunction(stk);
try {
while (stk->ip < 0xFFFFFFFF &&
@@ -2721,7 +2742,7 @@ execute:
cse[cse.size() - 2]->Push(gc, o);
cse.erase(cse.end() - 1);
current_function = cse.back();
GC::SetCurrentFunction(cse.back());
gc->BarrierEnd();
goto execute;
} else {
@@ -2729,8 +2750,13 @@ execute:
}
}
if (gc->UsingNullThreads())
gc->Collect();
if (gc->UsingNullThreads()) {
std::vector<THeapObject *> objs;
gc->Collect(objs);
for (auto &item : objs) {
delete item;
}
}
}
stk->mustReturn = false;
@@ -2764,7 +2790,7 @@ execute:
}
if (cse.size() == 1) {
current_function = nullptr;
GC::SetCurrentFunction(nullptr);
{
gc->BarrierBegin();
@@ -2817,7 +2843,7 @@ execute:
cse[cse.size() - 2]->Push(gc, o);
cse.erase(cse.end() - 1);
current_function = cse.back();
GC::SetCurrentFunction(cse.back());
gc->BarrierEnd();
for (auto item : callable) {
@@ -2846,7 +2872,7 @@ void CallStackEntry::Push(std::shared_ptr<GC> gc, TObject o) {
gc->BarrierEnd();
}
TObject CallStackEntry::Resume(GCList &ls) {
auto cse = current_function;
auto cse = GC::GetCurrentFunction();
InterperterThread *thrd = InterperterThread::Create(ls);
ls.GetGC()->BarrierBegin();
thrd->call_stack_entries.push_back(this);
@@ -2855,7 +2881,7 @@ TObject CallStackEntry::Resume(GCList &ls) {
thrd->Execute(ls.GetGC());
TObject v = thrd->call_stack_entries[0]->Pop(ls);
current_function = cse;
GC::SetCurrentFunction(cse);
return v;
}
TObject CallStackEntry::Pop(GCList &gc) {
@@ -2870,41 +2896,17 @@ TObject CallStackEntry::Pop(GCList &gc) {
}
InterperterThread *InterperterThread::Create(GCList &ls) {
InterperterThread *it = new InterperterThread();
std::shared_ptr<GC> _gc = ls.GetGC();
ls.Add(it);
_gc->Watch(it);
return it;
return ls.Create<InterperterThread>();
}
InterperterThread *InterperterThread::Create(GCList *ls) {
InterperterThread *it = new InterperterThread();
std::shared_ptr<GC> _gc = ls->GetGC();
ls->Add(it);
_gc->Watch(it);
return it;
return ls->Create<InterperterThread>();
}
CallStackEntry *CallStackEntry::Create(GCList &ls) {
CallStackEntry *cse = new CallStackEntry();
cse->mustReturn = false;
cse->srcline = -1;
cse->srcfile = "";
cse->thread = nullptr;
std::shared_ptr<GC> _gc = ls.GetGC();
ls.Add(cse);
_gc->Watch(cse);
return cse;
return ls.Create<CallStackEntry>();
}
CallStackEntry *CallStackEntry::Create(GCList *ls) {
CallStackEntry *cse = new CallStackEntry();
cse->mustReturn = false;
cse->srcline = -1;
cse->srcfile = "";
cse->thread = nullptr;
std::shared_ptr<GC> _gc = ls->GetGC();
ls->Add(cse);
_gc->Watch(cse);
return cse;
return ls->Create<CallStackEntry>();
}
void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure,
std::vector<TObject> args) {
@@ -2963,6 +2965,18 @@ void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure,
cse->env->DeclareVariable(trimStart(closure->closure->args[i]),
args[i]);
}
for (; i < closure->closure->args.size(); i++) {
auto &a = closure->closure->args[i];
if (a.size() > 1 && a[0] == '$') {
if (a[1] == '$') {
break;
}
cse->env->DeclareVariable(trimStart(a), Undefined());
} else {
break;
}
}
std::string back = closure->closure->args.empty()
? std::string()
: closure->closure->args.back();
@@ -2979,7 +2993,7 @@ void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure,
throw VMException("Too many arguments");
}
current_function = cse;
GC::SetCurrentFunction(cse);
this->call_stack_entries.push_back(cse);
ls.GetGC()->BarrierEnd();