#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 { thread_local CallStackEntry* current_function=nullptr; 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::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>(left) && std::holds_alternative>(right)) { auto& l = std::get>(left); auto& r = std::get>(right); cse.back()->Push(gc,l->ToEpoch() < r->ToEpoch()); } else if(std::holds_alternative>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(right)) { auto& l = std::get>(left); auto& r = std::get>(right); cse.back()->Push(gc,l->ToEpoch() > r->ToEpoch()); } else if(std::holds_alternative>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(right)) { auto& l = std::get>(left); auto& r = std::get>(right); cse.back()->Push(gc,l->ToEpoch() <= r->ToEpoch()); } else if(std::holds_alternative>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(right)) { auto& l = std::get>(left); auto& r = std::get>(right); cse.back()->Push(gc,l->ToEpoch() >= r->ToEpoch()); } else if(std::holds_alternative>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(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>(left) && std::holds_alternative>(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;iPop(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;iPop(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)) 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::exception& ex) { TDictionary* dict = TDictionary::Create(ls); auto gc = ls.GetGC(); auto myEx = dynamic_cast(&ex); if(myEx != nullptr) { stk->Push(gc, catchC->Call(ls,{myEx->exception})); } else { gc->BarrierBegin(); dict->SetValue("Type","NativeException"); dict->SetValue("Text",ex.what()); gc->BarrierEnd(); stk->Push(gc, catchC->Call(ls,{dict})); } } } 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.h" #undef VM_OPCODE_TABLE_INLINE execute: if(!cse.empty()) { auto stk = cse.back(); current_function = 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); current_function = cse.back(); gc->BarrierEnd(); goto execute; } else { return; } } if(gc->UsingNullThreads()) gc->Collect(); } 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) { current_function=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); current_function = 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 = current_function; 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); current_function = 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) { InterperterThread* it = new InterperterThread(); std::shared_ptr _gc = ls.GetGC(); ls.Add(it); _gc->Watch(it); return it; } InterperterThread* InterperterThread::Create(GCList* ls) { InterperterThread* it = new InterperterThread(); std::shared_ptr _gc = ls->GetGC(); ls->Add(it); _gc->Watch(it); return it; } CallStackEntry* CallStackEntry::Create(GCList& ls) { CallStackEntry* cse = new CallStackEntry(); cse->mustReturn=false; cse->srcline = -1; cse->srcfile = ""; cse->thread=nullptr; std::shared_ptr _gc = ls.GetGC(); ls.Add(cse); _gc->Watch(cse); return cse; } CallStackEntry* CallStackEntry::Create(GCList* ls) { CallStackEntry* cse = new CallStackEntry(); cse->mustReturn=false; cse->srcline = -1; cse->srcfile = ""; cse->thread=nullptr; std::shared_ptr _gc = ls->GetGC(); ls->Add(cse); _gc->Watch(cse); return cse; } 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;iclosure->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;iclosure->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]); } 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(;iAdd(args[i]); cse->env->DeclareVariable(trimStart(argName), lsArgs); i = args.size(); } if(icall_stack_entries.push_back(cse); ls.GetGC()->BarrierEnd(); } }