#include "CrossLang.hpp" #include "TessesFramework/Serialization/BitConverter.hpp" #include "TessesFramework/Streams/ByteReader.hpp" #include "TessesFramework/Uuid.hpp" #include #include #include #include #include #include #include namespace Tesses::CrossLang { TObject ExecuteFunction(GCList &ls, TCallable *callable, std::vector args) { return callable->Call(ls, args); } void InterperterThread::Mark() { if (this->marked) return; this->marked = true; for (auto item : this->call_stack_entries) { item->Mark(); } } #define TVM_HANDLER(hndl) \ if (hndl(gc)) \ goto execute typedef bool (InterperterThread::*opcode)(std::shared_ptr gc); bool InterperterThread::InterperterThread::Breakpoint(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto res = cse.back()->Pop(ls); auto env = cse.back()->env; if (!env->GetRootEnvironment()->HandleBreakpoint(gc, env, res)) { throw std::runtime_error("Breakpoint unhandled"); } return false; } bool InterperterThread::PushPrivateExpression(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto fn = cse.back(); auto re = fn->env->GetRootEnvironment(); if (re) { fn->Push(gc, re->GetPrivateFromFile(gc, fn->callable->file)); } else { throw VMException("No root environment for private expression"); } return false; } bool InterperterThread::Times(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) * std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) * std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) * std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) * std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator*"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator*", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator*"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator*", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Divide(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, Tesses::Framework::Filesystem::VFSPath( std::get(left)) / std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative( right)) { cse.back()->Push( gc, std::get(left) / std::get(right)); } else if (std::holds_alternative( left) && std::holds_alternative(right)) { cse.back()->Push( gc, std::get(left) / std::get(right)); } else if (std::holds_alternative( left) && std::holds_alternative( right)) { cse.back()->Push( gc, std::get(left) / std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) / std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) / std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) / std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) / std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator/"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator/", {right})); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator/", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator/"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator/", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Mod(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) % std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, fmod(std::get(left), std::get(right))); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push( gc, fmod(std::get(left), std::get(right))); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push( gc, fmod(std::get(left), std::get(right))); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator%"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator%", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator%"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator%", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Neg(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left)) { cse.back()->Push(gc, -std::get(left)); } else if (std::holds_alternative(left)) { cse.back()->Push(gc, -std::get(left)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator-"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator-", {})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator-"); gc->BarrierEnd(); return InvokeOne(ls, negfn, left); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator-", {})); return false; } else { cse.back()->Push(gc, nullptr); } } else { cse.back()->Push(gc, nullptr); } return false; } bool InterperterThread::LNot(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left)) { cse.back()->Push(gc, true); } else if (std::holds_alternative(left)) { cse.back()->Push(gc, true); } else if (std::holds_alternative(left)) { cse.back()->Push(gc, !std::get(left)); } else if (std::holds_alternative(left)) { cse.back()->Push(gc, !std::get(left)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator!"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, !natObj->ToBool()); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator!"); gc->BarrierEnd(); return InvokeOne(ls, negfn, left); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator!", {})); return false; } else { cse.back()->Push(gc, !ToBool(left)); } } else { cse.back()->Push(gc, !ToBool(left)); } return false; } bool InterperterThread::BNot(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left)) { cse.back()->Push(gc, ~std::get(left)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator~"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator~", {})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator~"); gc->BarrierEnd(); return InvokeOne(ls, negfn, left); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator~", {})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Lt(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r < 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) < std::get(right)); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->ToEpoch() < r->ToEpoch()); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() < r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator<"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator<", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator<", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Gt(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r > 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) > std::get(right)); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->ToEpoch() > r->ToEpoch()); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() > r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator>"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator>", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator>", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Lte(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r <= 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) <= std::get(right)); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->ToEpoch() <= r->ToEpoch()); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() <= r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator<="); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator<=", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<="); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator<=", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Gte(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r >= 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >= std::get(right)); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->ToEpoch() >= r->ToEpoch()); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() >= r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator>="); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator>=", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>="); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator>=", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Eq(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) == std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r == 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto l = std::get(left); auto r = std::get(right); return l == r; } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, (l->ToEpoch() == r->ToEpoch()) && (l->IsLocal() == r->IsLocal())); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() == r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto native = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator=="); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->Equals(gc, right)); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator=="); gc->BarrierEnd(); if (!std::holds_alternative(fn)) return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { auto res = dynDict->CallMethod(ls, "operator==", {right}); if (!std::holds_alternative(res) && std::holds_alternative(res)) { cse.back()->Push(gc, res); return false; } } else if (native != nullptr && std::holds_alternative(right)) { cse.back()->Push(gc, native->GetDestroyed()); return false; } if (std::holds_alternative(right)) { cse.back()->Push(gc, obj == std::get(right).obj); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else { cse.back()->Push(gc, Undefined()); } } else if (std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::NEq(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, false); return false; } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) != std::get(right)); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto lver = std::get(left); auto rver = std::get(right); auto r = lver.CompareTo(rver); cse.back()->Push(gc, r != 0); } else if (std::holds_alternative(left) && std::holds_alternative(right)) { auto l = std::get(left); auto r = std::get(right); return l != r; } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, !((l->ToEpoch() == r->ToEpoch()) && (l->IsLocal() == r->IsLocal()))); } else if (std::holds_alternative< std::shared_ptr>(left) && std::holds_alternative< std::shared_ptr>(right)) { auto &l = std::get>(left); auto &r = std::get>(right); cse.back()->Push(gc, l->TotalSeconds() != r->TotalSeconds()); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto native = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator!="); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, !natObj->Equals(gc, right)); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator!="); gc->BarrierEnd(); if (!std::holds_alternative(fn)) return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { auto res = dynDict->CallMethod(ls, "operator!=", {right}); if (!std::holds_alternative(res) && std::holds_alternative(res)) { cse.back()->Push(gc, res); return false; } } else if (native != nullptr && std::holds_alternative(right)) { cse.back()->Push(gc, !native->GetDestroyed()); return false; } if (std::holds_alternative(right)) { cse.back()->Push(gc, obj != std::get(right).obj); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else { cse.back()->Push(gc, Undefined()); } } else if (std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else if (std::holds_alternative(right)) { cse.back()->Push(gc, true); return false; } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::LShift(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) << (int)std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator<<"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator<<", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<<"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator<<", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::RShift(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) >> (int)std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator>>"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator>>", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>>"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator>>", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::BOr(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) | std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator|"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator|", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator|"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator|", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::XOr(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) ^ std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator^"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator^", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator^"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator^", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::BAnd(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if (std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc, std::get(left) & std::get(right)); } else if (std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); if (cls != nullptr) { gc->BarrierBegin(); auto obj = cls->GetValue(cse.back()->callable->className, "operator&"); gc->BarrierEnd(); TClosure *clos; TCallable *callable; if (GetObjectHeap(obj, clos)) { this->AddCallStackEntry(ls, clos, {right}); return true; } else if (GetObjectHeap(obj, callable)) { cse.back()->Push(gc, callable->Call(ls, {right})); return false; } cse.back()->Push(gc, Undefined()); return false; } else if (natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls, "operator&", {right})); return false; } else if (dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator&"); gc->BarrierEnd(); return InvokeTwo(ls, fn, left, right); } else if (dynDict != nullptr) { cse.back()->Push(gc, dynDict->CallMethod(ls, "operator&", {right})); return false; } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::InvokeOne(GCList &ls, TObject fn, TObject arg) { if (std::holds_alternative(fn)) { auto obj = dynamic_cast(std::get(fn).obj); if (obj != nullptr) { auto closure = dynamic_cast(obj); if (closure != nullptr) { if (!closure->closure->args.empty() && closure->closure->args[0] == "this") { this->AddCallStackEntry(ls, closure, {arg}); } else { this->AddCallStackEntry(ls, closure, {}); } } else { auto val = obj->Call(ls, {}); this->call_stack_entries.back()->Push(ls.GetGC(), val); return false; } return true; } } return false; } bool InterperterThread::ExecuteFunction(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; GCList ls(gc); auto res = stk->Pop(ls); if (std::holds_alternative(res)) { uint32_t n = (uint32_t)std::get(res); std::vector args; for (size_t i = 0; i < n; i++) { args.insert(args.begin(), {stk->Pop(ls)}); } TObject fn = stk->Pop(ls); if (std::holds_alternative(fn)) { if (args.size() == 3) { if (std::holds_alternative(args[1]) && std::holds_alternative(args[2])) { std::string key = std::get(args[1]); TList *ls = dynamic_cast( std::get(args[2]).obj); if (ls != nullptr) return ExecuteMethod2(gc, args[0], key, ls->items); } } stk->Push(gc, Undefined()); return false; } if (std::holds_alternative(fn)) { auto obj = dynamic_cast( std::get(fn).obj); if (obj != nullptr) { auto closure = dynamic_cast(obj); if (closure != nullptr) { this->AddCallStackEntry(ls, closure, args); return true; } else { auto val = obj->Call(ls, args); this->call_stack_entries.back()->Push(ls.GetGC(), val); return false; } return true; } stk->Push(gc, Undefined()); return false; } stk->Push(gc, Undefined()); } else stk->Push(gc, Undefined()); } return false; } bool InterperterThread::Yield(std::shared_ptr gc) { GCList ls(gc); std::vector &cse = this->call_stack_entries; if (!cse.empty()) { gc->BarrierBegin(); cse.back()->mustReturn = true; cse.back()->Push(gc, cse.back()); gc->BarrierEnd(); } return false; } bool InterperterThread::ExecuteMethod(std::shared_ptr gc) { GCList ls(gc); std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; auto cnt = stk->Pop(ls); if (std::holds_alternative(cnt)) { uint32_t n = (uint32_t)std::get(cnt); std::vector args; for (size_t i = 0; i < n; i++) { args.insert(args.begin(), {stk->Pop(ls)}); } TObject key = stk->Pop(ls); TObject instance = stk->Pop(ls); if (std::holds_alternative(key)) { return ExecuteMethod2(gc, instance, std::get(key), args); } stk->Push(gc, Undefined()); return false; } } return false; } bool InterperterThread::GetVariable(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); GCList ls(gc); auto key = stk->Pop(ls); if (std::holds_alternative(key)) { gc->BarrierBegin(); stk->Push(gc, stk->env->GetVariable(ls, std::get(key))); gc->BarrierEnd(); } else { throw VMException("[GETVARIABLE] Can't pop string."); } } return false; } bool InterperterThread::SetVariable(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); GCList ls(gc); auto value = stk->Pop(ls); auto key = stk->Pop(ls); TList *mls; if (std::holds_alternative(key)) { gc->BarrierBegin(); if (stk->env->HasConstForSet(std::get(key))) { gc->BarrierEnd(); ThrowConstError(std::get(key)); } stk->Push(gc, stk->env->SetVariable(ls, std::get(key), value)); gc->BarrierEnd(); } else if (GetObjectHeap(key, mls)) { gc->BarrierBegin(); TList *valueLs; TDynamicList *valueDynList; TDictionary *valueDict; TDynamicDictionary *valueDynDict; if (GetObjectHeap(value, valueLs)) { TDictionary *result = TDictionary::Create(ls); int64_t len = std::min(valueLs->Count(), mls->Count()); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueLs->Get(i); result->SetValue(mkey, val); if (stk->env->HasConstForSet(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->SetVariable(ls, mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynList)) { TDictionary *result = TDictionary::Create(ls); gc->BarrierEnd(); int64_t len = std::min(valueDynList->Count(ls), mls->Count()); gc->BarrierBegin(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynList->GetAt(ls, i); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForSet(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->SetVariable(ls, mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueDict->GetValue(mkey); result->SetValue(mkey, val); if (stk->env->HasConstForSet(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->SetVariable(ls, mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynDict->GetField(ls, mkey); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForSet(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->SetVariable(ls, mkey, val); } } stk->Push(gc, result); } else { int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { if (stk->env->HasConstForSet(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->SetVariable(ls, mkey, value); } } stk->Push(gc, value); } gc->BarrierEnd(); } else { throw VMException("[SETVARIABLE] Can't pop string."); } } return false; } bool InterperterThread::DeclareVariable(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); GCList ls(gc); auto value = stk->Pop(ls); auto key = stk->Pop(ls); TList *mls; if (std::holds_alternative(key)) { gc->BarrierBegin(); if (stk->env->HasConstForDeclare(std::get(key))) { gc->BarrierEnd(); ThrowConstError(std::get(key)); } stk->env->DeclareVariable(std::get(key), value); stk->Push(gc, value); gc->BarrierEnd(); } else if (GetObjectHeap(key, mls)) { gc->BarrierBegin(); TList *valueLs; TDynamicList *valueDynList; TDictionary *valueDict; TDynamicDictionary *valueDynDict; if (GetObjectHeap(value, valueLs)) { TDictionary *result = TDictionary::Create(ls); int64_t len = std::min(valueLs->Count(), mls->Count()); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueLs->Get(i); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynList)) { TDictionary *result = TDictionary::Create(ls); gc->BarrierEnd(); int64_t len = std::min(valueDynList->Count(ls), mls->Count()); gc->BarrierBegin(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynList->GetAt(ls, i); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueDict->GetValue(mkey); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynDict->GetField(ls, mkey); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareVariable(mkey, val); } } stk->Push(gc, result); } else { int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareVariable(mkey, value); } } stk->Push(gc, value); } gc->BarrierEnd(); } else { throw VMException("[DECLAREVARIABLE] Can't pop string, got type " + GetObjectTypeString(key) + " = " + ToString(gc, key) + "."); } } return false; } bool InterperterThread::DeclareConstVariable(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); GCList ls(gc); auto value = stk->Pop(ls); auto key = stk->Pop(ls); TList *mls; if (std::holds_alternative(key)) { gc->BarrierBegin(); if (stk->env->HasConstForDeclare(std::get(key))) { gc->BarrierEnd(); ThrowConstError(std::get(key)); } stk->env->DeclareConstVariable(std::get(key), value); stk->Push(gc, value); gc->BarrierEnd(); } else if (GetObjectHeap(key, mls)) { gc->BarrierBegin(); TList *valueLs; TDynamicList *valueDynList; TDictionary *valueDict; TDynamicDictionary *valueDynDict; if (GetObjectHeap(value, valueLs)) { TDictionary *result = TDictionary::Create(ls); int64_t len = std::min(valueLs->Count(), mls->Count()); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueLs->Get(i); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareConstVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynList)) { TDictionary *result = TDictionary::Create(ls); gc->BarrierEnd(); int64_t len = std::min(valueDynList->Count(ls), mls->Count()); gc->BarrierBegin(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynList->GetAt(ls, i); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareConstVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { auto val = valueDict->GetValue(mkey); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareConstVariable(mkey, val); } } stk->Push(gc, result); } else if (GetObjectHeap(value, valueDynDict)) { TDictionary *result = TDictionary::Create(ls); int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { gc->BarrierEnd(); auto val = valueDynDict->GetField(ls, mkey); gc->BarrierBegin(); result->SetValue(mkey, val); if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareConstVariable(mkey, val); } } stk->Push(gc, result); } else { int64_t len = mls->Count(); for (int64_t i = 0; i < len; i++) { std::string mkey; auto item = mls->Get(i); if (GetObject(item, mkey)) { if (stk->env->HasConstForDeclare(mkey)) { gc->BarrierEnd(); ThrowConstError(mkey); } stk->env->DeclareConstVariable(mkey, value); } } stk->Push(gc, value); } gc->BarrierEnd(); } else { throw VMException( "[DECLARECONSTVARIABLE] Can't pop string, got type " + GetObjectTypeString(key) + " = " + ToString(gc, key) + "."); } } return false; } bool InterperterThread::PushResourceStream(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); if (n >= stk->callable->file->resources.size()) throw VMException("Can't read resource."); stk->ip = stk->ip + 4; gc->BarrierBegin(); GCList ls(gc); // TByteArray* arr = TByteArray::Create(ls); // arr->data = stk->callable->file->resources[n]; stk->Push( gc, std::make_shared(gc, stk->callable->file, n)); gc->BarrierEnd(); } else { throw VMException("Can't read chunk."); } } return false; } bool InterperterThread::PushResource(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); if (n >= stk->callable->file->resources.size()) throw VMException("Can't read resource."); stk->ip = stk->ip + 4; gc->BarrierBegin(); GCList ls(gc); TByteArray *arr = TByteArray::Create(ls); arr->data = stk->callable->file->resources[n]; stk->Push(gc, arr); gc->BarrierEnd(); } else { throw VMException("Can't read chunk."); } } return false; } bool InterperterThread::Throw(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto _res2 = cse.back()->Pop(ls); if (!std::holds_alternative(_res2)) { auto env = cse.back()->env; if (!env->GetRootEnvironment()->HandleException(gc, env, _res2)) { TNativeException *nex; if (GetObjectHeap(_res2, nex)) { nex->ThrowIt(); } throw VMByteCodeException(gc, _res2, cse.back()); } } return false; } bool InterperterThread::PushResourceDirectory(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; GCList ls(gc); auto _res2 = cse.back()->Pop(ls); TDictionary *dict; if (GetObjectHeap(_res2, dict)) { cse.back()->Push(gc, std::make_shared(gc, dict)); } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::JumpIfDefined(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls(gc); auto _res2 = stk->Pop(ls); stk->ip = stk->ip + 4; if (!std::holds_alternative(_res2) && !std::holds_alternative(_res2)) { stk->ip = n; stk->Push(gc, _res2); } } else throw VMException("Can't read jmpifdefined pc."); return false; } bool InterperterThread::JumpIfBreak(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls(gc); auto _res2 = stk->Pop(ls); stk->ip = stk->ip + 4; if (std::holds_alternative(_res2)) stk->ip = n; else stk->Push(gc, _res2); } else throw VMException("Can't read jmpifbreak pc."); return false; } bool InterperterThread::JumpIfContinue(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls(gc); auto _res2 = stk->Pop(ls); stk->ip = stk->ip + 4; if (std::holds_alternative(_res2)) stk->ip = n; else stk->Push(gc, _res2); } else throw VMException("Can't read jmpifcontinue pc."); return false; } bool InterperterThread::JumpUndefined(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls(gc); auto _res2 = stk->Pop(ls); stk->ip = stk->ip + 4; if (std::holds_alternative(_res2)) stk->ip = n; else stk->Push(gc, _res2); } else throw VMException("Can't read jmpundefined pc."); return false; } bool InterperterThread::Jump(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); stk->ip = n; } else throw VMException("Can't read jmp pc."); return false; } bool InterperterThread::PushNull(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, nullptr); return false; } bool InterperterThread::PushBreak(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, TBreak()); return false; } bool InterperterThread::PushContinue(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, TContinue()); return false; } bool InterperterThread::PushUndefined(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, Undefined()); return false; } bool InterperterThread::LineInfo(std::shared_ptr gc) { GCList ls(gc); std::vector &cse = this->call_stack_entries; auto stk = cse.back(); auto file = stk->Pop(ls); auto line = stk->Pop(ls); // Set the fields in this cse GetObject(file, stk->srcfile); GetObject(line, stk->srcline); // TODO: implement lines (this will make the language work until we get it // rigged up) return false; } bool InterperterThread::PushFalse(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, false); return false; } bool InterperterThread::PushTrue(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->Push(gc, true); return false; } bool InterperterThread::CreateDictionary(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); TDictionary *dict = TDictionary::Create(ls); stk->Push(gc, dict); return false; } bool InterperterThread::Nop(std::shared_ptr gc) { return false; } bool InterperterThread::AppendList(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); gc->BarrierBegin(); auto obj = stk->Pop(ls); auto objhold = stk->Pop(ls); if (std::holds_alternative(objhold)) { auto list = dynamic_cast(std::get(objhold).obj); if (list != nullptr) { list->Add(obj); } /* if(dict != nullptr) { auto potential_str = stk->Pop(ls); if(std::holds_alternative(potential_str)) { dict->SetValue(std::get(potential_str), stk->Pop(ls)); } }*/ } stk->Push(gc, objhold); gc->BarrierEnd(); return false; } bool InterperterThread::AppendDictionary(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); gc->BarrierBegin(); auto value = stk->Pop(ls); auto k = stk->Pop(ls); auto objhold = stk->Pop(ls); if (std::holds_alternative(objhold) && std::holds_alternative(k)) { auto dict = dynamic_cast( std::get(objhold).obj); auto cls = dynamic_cast( std::get(objhold).obj); if (dict != nullptr) { dict->SetValue(std::get(k), value); } else if (cls != nullptr) { auto obj = cls->GetValue(cse.back()->callable->className, "set" + std::get(k)); TCallable *callable; if (GetObjectHeap(obj, callable)) { gc->BarrierEnd(); callable->Call(ls, {value}); gc->BarrierBegin(); } else { cls->SetValue(cse.back()->callable->className, std::get(k), value); } } } stk->Push(gc, objhold); gc->BarrierEnd(); return false; } bool InterperterThread::CreateArray(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); TList *dict = TList::Create(ls); stk->Push(gc, dict); return false; } bool InterperterThread::Pop(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); stk->Pop(ls); return false; } bool InterperterThread::TryCatch(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); auto catchFn = stk->Pop(ls); auto tryFn = stk->Pop(ls); TCallable *tryC; TCallable *catchC; if (GetObjectHeap(tryFn, tryC) && GetObjectHeap(catchFn, catchC)) { try { stk->Push(gc, tryC->Call(ls, {})); } 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) { stk->Push(gc, catchC->Call(ls, {std::string{ex != nullptr ? ex : ""}})); } catch (std::runtime_error &ex) { stk->Push( gc, catchC->Call(ls, {TNativeObject::Create( ls, ex.what(), "RuntimeException")})); } catch (VMException &ex) { stk->Push( gc, catchC->Call(ls, {TNativeObject::Create( 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( ls, ex.what(), std::current_exception())})); } catch (...) { stk->Push(gc, catchC->Call(ls, {TNativeObject::Create( ls, "", std::current_exception())})); } } return false; } bool InterperterThread::JumpConditional(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); if (stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n = BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls2(gc); auto _res2 = stk->Pop(ls2); auto _res = ToBool(_res2); stk->ip = stk->ip + 4; if (_res) stk->ip = n; } else throw VMException("Can't read jmpc pc."); return false; } bool InterperterThread::PushClosure(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); if (n >= stk->callable->file->chunks.size()) throw VMException("Can't read chunk."); stk->ip = stk->ip + 4; gc->BarrierBegin(); GCList ls(gc); TClosure *closure = TClosure::Create(ls, stk->env, stk->callable->file, n, true); closure->className = cse.back()->callable->className; stk->Push(gc, closure); gc->BarrierEnd(); } else { throw VMException("Can't read chunk."); } } return false; } bool InterperterThread::PushScopelessClosure(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); if (n >= stk->callable->file->chunks.size()) throw VMException("Can't read chunk."); stk->ip = stk->ip + 4; gc->BarrierBegin(); GCList ls(gc); TClosure *closure = TClosure::Create(ls, stk->env, stk->callable->file, n, false); closure->className = stk->callable->className; stk->Push(gc, closure); gc->BarrierEnd(); } else { throw VMException("Can't read chunk."); } } return false; } bool InterperterThread::PushString(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); if (n < stk->callable->file->strings.size()) stk->Push(gc, stk->callable->file->strings[n]); else throw VMException("Can't read string."); stk->ip = stk->ip + 4; } } return false; } bool InterperterThread::PushLong(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 8 <= code.size()) { uint64_t n = BitConverter::ToUint64BE(code[stk->ip]); stk->Push(gc, (int64_t)n); stk->ip = stk->ip + 8; } } return false; } bool InterperterThread::PushChar(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 1 <= code.size()) { char c = (char)code[stk->ip]; stk->Push(gc, c); stk->ip = stk->ip + 1; } } return false; } bool InterperterThread::PushDouble(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; if (!cse.empty()) { auto stk = cse.back(); std::vector &code = stk->callable->closure->code; if (stk->ip + 8 <= code.size()) { double dbl = BitConverter::ToDoubleBE(code[stk->ip]); stk->Push(gc, dbl); stk->ip = stk->ip + 8; } } return false; } bool InterperterThread::Return(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); stk->ip = (uint32_t)stk->callable->closure->code.size(); return false; } bool InterperterThread::ScopeBegin(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); gc->BarrierBegin(); GCList ls(gc); stk->env = stk->env->GetSubEnvironment(ls); stk->scopes++; gc->BarrierEnd(); return false; } bool InterperterThread::Defer(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); gc->BarrierBegin(); GCList ls(gc); auto item = stk->Pop(ls); TCallable *call; if (GetObjectHeap(item, call)) cse.back()->env->defers.insert(cse.back()->env->defers.begin(), {call}); gc->BarrierEnd(); return false; } bool InterperterThread::Dup(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); GCList ls(gc); auto res = stk->Pop(ls); stk->Push(gc, res); stk->Push(gc, res); return false; } bool InterperterThread::ScopeEndTimes(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); gc->BarrierBegin(); GCList ls(gc); std::vector callable; std::vector &code = stk->callable->closure->code; if (stk->ip + 4 <= code.size()) { uint32_t n = BitConverter::ToUint32BE(code[stk->ip]); stk->ip += 4; for (uint32_t i = 0; i < n; i++) { if (!stk->env->defers.empty()) { ls.Add(stk->env); callable.insert(callable.end(), stk->env->defers.begin(), stk->env->defers.end()); } stk->scopes--; stk->env = stk->env->GetParentEnvironment(); } } gc->BarrierEnd(); for (auto item : callable) { GCList ls2(gc); item->Call(ls2, {}); } return false; } bool InterperterThread::ScopeEnd(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); gc->BarrierBegin(); GCList ls(gc); std::vector callable; if (!stk->env->defers.empty()) { ls.Add(stk->env); callable.insert(callable.end(), stk->env->defers.begin(), stk->env->defers.end()); } stk->scopes--; stk->env = stk->env->GetParentEnvironment(); gc->BarrierEnd(); for (auto item : callable) { GCList ls2(gc); item->Call(ls2, {}); } return false; } bool InterperterThread::PushRelativePath(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); auto p = Framework::Filesystem::VFSPath(); p.relative = true; p.path = {}; stk->Push(gc, p); return false; } bool InterperterThread::PushRootPath(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); auto p = Framework::Filesystem::VFSPath(); p.relative = false; p.path = {}; stk->Push(gc, p); return false; } bool InterperterThread::Illegal(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; auto stk = cse.back(); char chr[3]; snprintf(chr, 3, "%02X", stk->callable->closure->code[stk->ip - 1]); throw VMException("Illegal instruction: 0x" + std::string(chr) + "."); } void InterperterThread::Execute(std::shared_ptr gc) { std::vector &cse = this->call_stack_entries; #define VM_OPCODE_TABLE_INLINE #include "vm_opcode_table.def" #undef VM_OPCODE_TABLE_INLINE execute: if (!cse.empty()) { auto stk = cse.back(); GC::SetCurrentFunction(stk); try { while (stk->ip < 0xFFFFFFFF && stk->ip < stk->callable->closure->code.size()) { uint32_t ip = stk->ip; stk->ip = ip + 1; if (((*this).*(opcodes[stk->callable->closure->code[ip]]))(gc)) goto execute; if (stk->mustReturn) { stk->mustReturn = false; if (cse.size() > 1) { GCList ls(gc); TObject o = cse[cse.size() - 1]->Pop(ls); cse[cse.size() - 2]->Push(gc, o); cse.erase(cse.end() - 1); GC::SetCurrentFunction(cse.back()); gc->BarrierEnd(); goto execute; } else { return; } } if (gc->UsingNullThreads()) { std::vector objs; gc->Collect(objs); for (auto &item : objs) { delete item; } } } stk->mustReturn = false; } catch (...) { { gc->BarrierBegin(); GCList ls(gc); std::vector callable; while (!cse.empty()) { auto r = cse.back(); auto e = r->env; for (uint32_t i = 0; i < r->scopes; i++) { if (!e->defers.empty()) { ls.Add(e); callable.insert(callable.end(), e->defers.begin(), e->defers.end()); } e = e->GetParentEnvironment(); } cse.erase(cse.end() - 1); } gc->BarrierEnd(); for (auto item : callable) { GCList ls2(gc); item->Call(ls2, {}); } } std::rethrow_exception(std::current_exception()); } if (cse.size() == 1) { GC::SetCurrentFunction(nullptr); { gc->BarrierBegin(); GCList ls(gc); std::vector callable; auto r = cse.back(); auto e = r->env; for (uint32_t i = 0; i < r->scopes; i++) { if (!e->defers.empty()) { ls.Add(e); callable.insert(callable.end(), e->defers.begin(), e->defers.end()); } e = e->GetParentEnvironment(); } gc->BarrierEnd(); for (auto item : callable) { GCList ls2(gc); item->Call(ls2, {}); } } return; } else { { gc->BarrierBegin(); GCList ls(gc); std::vector callable; auto r = cse.back(); auto e = r->env; for (uint32_t i = 0; i < r->scopes; i++) { if (!e->defers.empty()) { ls.Add(e); callable.insert(callable.end(), e->defers.begin(), e->defers.end()); } e = e->GetParentEnvironment(); } TObject o = cse[cse.size() - 1]->Pop(ls); cse[cse.size() - 2]->Push(gc, o); cse.erase(cse.end() - 1); GC::SetCurrentFunction(cse.back()); gc->BarrierEnd(); for (auto item : callable) { GCList ls2(gc); item->Call(ls2, {}); } } goto execute; } } } void CallStackEntry::Mark() { if (this->marked) return; this->marked = true; this->env->Mark(); this->callable->Mark(); for (auto item : this->stack) GC::Mark(item); } void CallStackEntry::Push(std::shared_ptr gc, TObject o) { gc->BarrierBegin(); this->stack.push_back(o); gc->BarrierEnd(); } TObject CallStackEntry::Resume(GCList &ls) { auto cse = GC::GetCurrentFunction(); InterperterThread *thrd = InterperterThread::Create(ls); ls.GetGC()->BarrierBegin(); thrd->call_stack_entries.push_back(this); ls.GetGC()->BarrierEnd(); thrd->Execute(ls.GetGC()); TObject v = thrd->call_stack_entries[0]->Pop(ls); GC::SetCurrentFunction(cse); return v; } TObject CallStackEntry::Pop(GCList &gc) { if (this->stack.empty()) return Undefined(); gc.GetGC()->BarrierBegin(); TObject o = this->stack[this->stack.size() - 1]; gc.Add(o); this->stack.erase(this->stack.begin() + this->stack.size() - 1); gc.GetGC()->BarrierEnd(); return o; } InterperterThread *InterperterThread::Create(GCList &ls) { return ls.Create(); } InterperterThread *InterperterThread::Create(GCList *ls) { return ls->Create(); } CallStackEntry *CallStackEntry::Create(GCList &ls) { return ls.Create(); } CallStackEntry *CallStackEntry::Create(GCList *ls) { return ls->Create(); } void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure, std::vector args) { ls.GetGC()->BarrierBegin(); CallStackEntry *cse = CallStackEntry::Create(ls); cse->thread = this; cse->callable = closure; cse->env = closure->chunkId == 0 ? closure->env : closure->ownScope ? closure->env->GetSubEnvironment(ls) : closure->env; cse->ip = 0; if (closure->closure->args.empty() && closure->chunkId != 0) { TList *list = TList::Create(ls); list->items = args; cse->env->DeclareVariable("arguments", list); } else { auto requiredArguments = [closure]() -> size_t { for (size_t i = 0; i < closure->closure->args.size(); i++) { if (closure->closure->args[i].find("$") == 0) { return i; } } return closure->closure->args.size(); }; auto optionalArguments = [closure](size_t argLen) -> size_t { for (size_t i = 0; i < closure->closure->args.size(); i++) { if (closure->closure->args[i].find("$$") == 0) { return std::min(argLen, i); } } return std::min(argLen, closure->closure->args.size()); }; auto trimStart = [](std::string txt) -> std::string { if (txt.empty()) return {}; if (txt[0] != '$') return txt; auto idx = txt.find_first_not_of('$'); if (idx == std::string::npos) return {}; return txt.substr(idx); }; size_t required = requiredArguments(); if (args.size() < required) { throw VMException("Called a function that expected at least " + std::to_string(required) + " args but got " + std::to_string(args.size())); } size_t i; for (i = 0; i < optionalArguments(args.size()); i++) { 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(); if (i == closure->closure->args.size() - 1 && back.size() > 2 && back[0] == '$' && back[1] == '$') { auto argName = closure->closure->args[i]; auto lsArgs = TList::Create(ls); for (; i < args.size(); i++) lsArgs->Add(args[i]); cse->env->DeclareVariable(trimStart(argName), lsArgs); i = args.size(); } if (i < args.size()) throw VMException("Too many arguments"); } GC::SetCurrentFunction(cse); this->call_stack_entries.push_back(cse); ls.GetGC()->BarrierEnd(); } } // namespace Tesses::CrossLang