mirror of
https://git.tesses.org/tesses50/crosslang.git
synced 2026-10-01 09:14:12 +00:00
3003 lines
109 KiB
C++
3003 lines
109 KiB
C++
#include "CrossLang.hpp"
|
|
#include "TessesFramework/Serialization/BitConverter.hpp"
|
|
#include "TessesFramework/Streams/ByteReader.hpp"
|
|
#include "TessesFramework/Uuid.hpp"
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <exception>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <variant>
|
|
|
|
namespace Tesses::CrossLang {
|
|
|
|
TObject ExecuteFunction(GCList &ls, TCallable *callable,
|
|
std::vector<TObject> 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> gc);
|
|
|
|
bool InterperterThread::InterperterThread::Breakpoint(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) * std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) * std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) * std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) * std::get<double>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, Tesses::Framework::Filesystem::VFSPath(
|
|
std::get<std::string>(left)) /
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
|
|
right)) {
|
|
cse.back()->Push(
|
|
gc, std::get<std::string>(left) /
|
|
std::get<Tesses::Framework::Filesystem::VFSPath>(right));
|
|
|
|
}
|
|
|
|
else if (std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
|
|
left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(
|
|
gc, std::get<Tesses::Framework::Filesystem::VFSPath>(left) /
|
|
std::get<std::string>(right));
|
|
|
|
}
|
|
|
|
else if (std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
|
|
left) &&
|
|
std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
|
|
right)) {
|
|
cse.back()->Push(
|
|
gc, std::get<Tesses::Framework::Filesystem::VFSPath>(left) /
|
|
std::get<Tesses::Framework::Filesystem::VFSPath>(right));
|
|
|
|
}
|
|
|
|
else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) / std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) / std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) / std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) / std::get<double>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) % std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc,
|
|
fmod(std::get<double>(left), std::get<double>(right)));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(
|
|
gc, fmod(std::get<double>(left), std::get<int64_t>(right)));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(
|
|
gc, fmod(std::get<int64_t>(left), std::get<double>(right)));
|
|
}
|
|
|
|
else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left)) {
|
|
cse.back()->Push(gc, -std::get<int64_t>(left));
|
|
} else if (std::holds_alternative<double>(left)) {
|
|
cse.back()->Push(gc, -std::get<double>(left));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<Undefined>(left)) {
|
|
cse.back()->Push(gc, true);
|
|
} else if (std::holds_alternative<std::nullptr_t>(left)) {
|
|
cse.back()->Push(gc, true);
|
|
}
|
|
|
|
else if (std::holds_alternative<int64_t>(left)) {
|
|
cse.back()->Push(gc, !std::get<int64_t>(left));
|
|
}
|
|
|
|
else if (std::holds_alternative<bool>(left)) {
|
|
cse.back()->Push(gc, !std::get<bool>(left));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left)) {
|
|
cse.back()->Push(gc, ~std::get<int64_t>(left));
|
|
}
|
|
|
|
else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) < std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) < std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) < std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) < std::get<double>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) < std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) < std::get<char>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) < std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r < 0);
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) <
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, l->ToEpoch() < r->ToEpoch());
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() < r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) > std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) > std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) > std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) > std::get<double>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) > std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) > std::get<char>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) > std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r > 0);
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) >
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, l->ToEpoch() > r->ToEpoch());
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() > r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) <= std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) <= std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<double>(left) <= std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) <= std::get<double>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) <= std::get<char>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) <= std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) <= std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r <= 0);
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) <=
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, l->ToEpoch() <= r->ToEpoch());
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() <= r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) >= std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) >= std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<double>(left) >= std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) >= std::get<double>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) >= std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) >= std::get<char>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) >= std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r >= 0);
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) >=
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, l->ToEpoch() >= r->ToEpoch());
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() >= r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
if (std::holds_alternative<std::nullptr_t>(left) &&
|
|
std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
}
|
|
|
|
else if (std::holds_alternative<Undefined>(left) &&
|
|
std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
}
|
|
|
|
else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) == std::get<int64_t>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) == std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<double>(left) == std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) == std::get<double>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) ==
|
|
std::get<std::string>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<bool>(left) &&
|
|
std::holds_alternative<bool>(right)) {
|
|
cse.back()->Push(gc, std::get<bool>(left) == std::get<bool>(right));
|
|
}
|
|
|
|
else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) == std::get<char>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) == std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) == std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r == 0);
|
|
} else if (std::holds_alternative<Tesses::Framework::Uuid>(left) &&
|
|
std::holds_alternative<Tesses::Framework::Uuid>(right)) {
|
|
auto l = std::get<Tesses::Framework::Uuid>(left);
|
|
auto r = std::get<Tesses::Framework::Uuid>(right);
|
|
|
|
return l == r;
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, (l->ToEpoch() == r->ToEpoch()) &&
|
|
(l->IsLocal() == r->IsLocal()));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() == r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto native = dynamic_cast<TNative *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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<Undefined>(fn))
|
|
return InvokeTwo(ls, fn, left, right);
|
|
|
|
}
|
|
|
|
else if (dynDict != nullptr) {
|
|
auto res = dynDict->CallMethod(ls, "operator==", {right});
|
|
if (!std::holds_alternative<std::nullptr_t>(res) &&
|
|
std::holds_alternative<Undefined>(res)) {
|
|
cse.back()->Push(gc, res);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
else if (native != nullptr &&
|
|
std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, native->GetDestroyed());
|
|
return false;
|
|
}
|
|
|
|
if (std::holds_alternative<THeapObjectHolder>(right)) {
|
|
cse.back()->Push(gc, obj == std::get<THeapObjectHolder>(right).obj);
|
|
return false;
|
|
}
|
|
|
|
else if (std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else if (std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else {
|
|
cse.back()->Push(gc, Undefined());
|
|
}
|
|
|
|
}
|
|
|
|
else if (std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else if (std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else {
|
|
cse.back()->Push(gc, Undefined());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool InterperterThread::NEq(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<std::nullptr_t>(left) &&
|
|
std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else if (std::holds_alternative<Undefined>(left) &&
|
|
std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, false);
|
|
return false;
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) != std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc, std::get<double>(left) != std::get<double>(right));
|
|
} else if (std::holds_alternative<double>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<double>(left) != std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<double>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) != std::get<double>(right));
|
|
} else if (std::holds_alternative<std::string>(left) &&
|
|
std::holds_alternative<std::string>(right)) {
|
|
cse.back()->Push(gc, std::get<std::string>(left) !=
|
|
std::get<std::string>(right));
|
|
} else if (std::holds_alternative<bool>(left) &&
|
|
std::holds_alternative<bool>(right)) {
|
|
cse.back()->Push(gc, std::get<bool>(left) != std::get<bool>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) != std::get<char>(right));
|
|
} else if (std::holds_alternative<char>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<char>(left) != std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<char>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) != std::get<char>(right));
|
|
} else if (std::holds_alternative<TVMVersion>(left) &&
|
|
std::holds_alternative<TVMVersion>(right)) {
|
|
auto lver = std::get<TVMVersion>(left);
|
|
auto rver = std::get<TVMVersion>(right);
|
|
auto r = lver.CompareTo(rver);
|
|
cse.back()->Push(gc, r != 0);
|
|
} else if (std::holds_alternative<Tesses::Framework::Uuid>(left) &&
|
|
std::holds_alternative<Tesses::Framework::Uuid>(right)) {
|
|
auto l = std::get<Tesses::Framework::Uuid>(left);
|
|
auto r = std::get<Tesses::Framework::Uuid>(right);
|
|
|
|
return l != r;
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
|
|
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
|
|
cse.back()->Push(gc, !((l->ToEpoch() == r->ToEpoch()) &&
|
|
(l->IsLocal() == r->IsLocal())));
|
|
} else if (std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
|
|
std::holds_alternative<
|
|
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
|
|
auto &l =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
|
|
auto &r =
|
|
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
|
|
cse.back()->Push(gc, l->TotalSeconds() != r->TotalSeconds());
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
auto native = dynamic_cast<TNative *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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<Undefined>(fn))
|
|
return InvokeTwo(ls, fn, left, right);
|
|
}
|
|
|
|
else if (dynDict != nullptr) {
|
|
|
|
auto res = dynDict->CallMethod(ls, "operator!=", {right});
|
|
if (!std::holds_alternative<std::nullptr_t>(res) &&
|
|
std::holds_alternative<Undefined>(res)) {
|
|
cse.back()->Push(gc, res);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
else if (native != nullptr &&
|
|
std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, !native->GetDestroyed());
|
|
return false;
|
|
}
|
|
if (std::holds_alternative<THeapObjectHolder>(right)) {
|
|
cse.back()->Push(gc, obj != std::get<THeapObjectHolder>(right).obj);
|
|
return false;
|
|
} else if (std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
} else if (std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
} else {
|
|
cse.back()->Push(gc, Undefined());
|
|
}
|
|
|
|
} else if (std::holds_alternative<Undefined>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
} else if (std::holds_alternative<std::nullptr_t>(right)) {
|
|
cse.back()->Push(gc, true);
|
|
return false;
|
|
} else {
|
|
cse.back()->Push(gc, Undefined());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool InterperterThread::LShift(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left)
|
|
<< (int)std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc, std::get<int64_t>(left) >>
|
|
(int)std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) | std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) ^ std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto right = cse.back()->Pop(ls);
|
|
auto left = cse.back()->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(left) &&
|
|
std::holds_alternative<int64_t>(right)) {
|
|
cse.back()->Push(gc,
|
|
std::get<int64_t>(left) & std::get<int64_t>(right));
|
|
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
|
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
|
auto dict = dynamic_cast<TDictionary *>(obj);
|
|
|
|
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
|
|
auto natObj = dynamic_cast<TNativeObject *>(obj);
|
|
auto cls = dynamic_cast<TClassObject *>(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<THeapObjectHolder>(fn)) {
|
|
|
|
auto obj =
|
|
dynamic_cast<TCallable *>(std::get<THeapObjectHolder>(fn).obj);
|
|
if (obj != nullptr) {
|
|
auto closure = dynamic_cast<TClosure *>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &code = stk->callable->closure->code;
|
|
GCList ls(gc);
|
|
auto res = stk->Pop(ls);
|
|
|
|
if (std::holds_alternative<int64_t>(res)) {
|
|
uint32_t n = (uint32_t)std::get<int64_t>(res);
|
|
|
|
std::vector<TObject> 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<MethodInvoker>(fn)) {
|
|
if (args.size() == 3) {
|
|
|
|
if (std::holds_alternative<std::string>(args[1]) &&
|
|
std::holds_alternative<THeapObjectHolder>(args[2])) {
|
|
std::string key = std::get<std::string>(args[1]);
|
|
TList *ls = dynamic_cast<TList *>(
|
|
std::get<THeapObjectHolder>(args[2]).obj);
|
|
if (ls != nullptr)
|
|
return ExecuteMethod2(gc, args[0], key, ls->items);
|
|
}
|
|
}
|
|
stk->Push(gc, Undefined());
|
|
return false;
|
|
}
|
|
|
|
if (std::holds_alternative<THeapObjectHolder>(fn)) {
|
|
|
|
auto obj = dynamic_cast<TCallable *>(
|
|
std::get<THeapObjectHolder>(fn).obj);
|
|
if (obj != nullptr) {
|
|
auto closure = dynamic_cast<TClosure *>(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> gc) {
|
|
GCList ls(gc);
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
GCList ls(gc);
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &code = stk->callable->closure->code;
|
|
|
|
auto cnt = stk->Pop(ls);
|
|
if (std::holds_alternative<int64_t>(cnt)) {
|
|
uint32_t n = (uint32_t)std::get<int64_t>(cnt);
|
|
|
|
std::vector<TObject> 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<std::string>(key)) {
|
|
return ExecuteMethod2(gc, instance, std::get<std::string>(key),
|
|
args);
|
|
}
|
|
stk->Push(gc, Undefined());
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InterperterThread::GetVariable(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
GCList ls(gc);
|
|
auto key = stk->Pop(ls);
|
|
if (std::holds_alternative<std::string>(key)) {
|
|
gc->BarrierBegin();
|
|
stk->Push(gc,
|
|
stk->env->GetVariable(ls, std::get<std::string>(key)));
|
|
gc->BarrierEnd();
|
|
} else {
|
|
throw VMException("[GETVARIABLE] Can't pop string.");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool InterperterThread::SetVariable(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &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<std::string>(key)) {
|
|
gc->BarrierBegin();
|
|
|
|
if (stk->env->HasConstForSet(std::get<std::string>(key))) {
|
|
gc->BarrierEnd();
|
|
ThrowConstError(std::get<std::string>(key));
|
|
}
|
|
stk->Push(gc, stk->env->SetVariable(ls, std::get<std::string>(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> gc) {
|
|
std::vector<CallStackEntry *> &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<std::string>(key)) {
|
|
gc->BarrierBegin();
|
|
if (stk->env->HasConstForDeclare(std::get<std::string>(key))) {
|
|
gc->BarrierEnd();
|
|
ThrowConstError(std::get<std::string>(key));
|
|
}
|
|
stk->env->DeclareVariable(std::get<std::string>(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> gc) {
|
|
std::vector<CallStackEntry *> &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<std::string>(key)) {
|
|
gc->BarrierBegin();
|
|
if (stk->env->HasConstForDeclare(std::get<std::string>(key))) {
|
|
gc->BarrierEnd();
|
|
ThrowConstError(std::get<std::string>(key));
|
|
}
|
|
stk->env->DeclareConstVariable(std::get<std::string>(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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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<EmbedStream>(gc, stk->callable->file, n));
|
|
|
|
gc->BarrierEnd();
|
|
} else {
|
|
throw VMException("Can't read chunk.");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InterperterThread::PushResource(std::shared_ptr<GC> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
GCList ls(gc);
|
|
auto _res2 = cse.back()->Pop(ls);
|
|
|
|
if (!std::holds_alternative<Undefined>(_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> gc) {
|
|
std::vector<CallStackEntry *> &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<EmbedDirectory>(gc, dict));
|
|
} else {
|
|
cse.back()->Push(gc, Undefined());
|
|
}
|
|
return false;
|
|
}
|
|
bool InterperterThread::JumpIfDefined(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
if (stk->ip + 4 <= stk->callable->closure->code.size()) {
|
|
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<Undefined>(_res2) &&
|
|
!std::holds_alternative<std::nullptr_t>(_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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<TBreak>(_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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<TContinue>(_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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<Undefined>(_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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, nullptr);
|
|
return false;
|
|
}
|
|
bool InterperterThread::PushBreak(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, TBreak());
|
|
return false;
|
|
}
|
|
bool InterperterThread::PushContinue(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, TContinue());
|
|
return false;
|
|
}
|
|
bool InterperterThread::PushUndefined(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, Undefined());
|
|
return false;
|
|
}
|
|
bool InterperterThread::LineInfo(std::shared_ptr<GC> gc) {
|
|
GCList ls(gc);
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, false);
|
|
return false;
|
|
}
|
|
bool InterperterThread::PushTrue(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
|
|
stk->Push(gc, true);
|
|
return false;
|
|
}
|
|
bool InterperterThread::CreateDictionary(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) { return false; }
|
|
bool InterperterThread::AppendList(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<THeapObjectHolder>(objhold)) {
|
|
auto list =
|
|
dynamic_cast<TList *>(std::get<THeapObjectHolder>(objhold).obj);
|
|
if (list != nullptr) {
|
|
list->Add(obj);
|
|
}
|
|
/*
|
|
if(dict != nullptr)
|
|
{
|
|
auto potential_str = stk->Pop(ls);
|
|
if(std::holds_alternative<std::string>(potential_str))
|
|
{
|
|
dict->SetValue(std::get<std::string>(potential_str),
|
|
stk->Pop(ls));
|
|
}
|
|
}*/
|
|
}
|
|
|
|
stk->Push(gc, objhold);
|
|
|
|
gc->BarrierEnd();
|
|
return false;
|
|
}
|
|
bool InterperterThread::AppendDictionary(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<THeapObjectHolder>(objhold) &&
|
|
std::holds_alternative<std::string>(k)) {
|
|
auto dict = dynamic_cast<TDictionary *>(
|
|
std::get<THeapObjectHolder>(objhold).obj);
|
|
auto cls = dynamic_cast<TClassObject *>(
|
|
std::get<THeapObjectHolder>(objhold).obj);
|
|
|
|
if (dict != nullptr) {
|
|
dict->SetValue(std::get<std::string>(k), value);
|
|
} else if (cls != nullptr) {
|
|
auto obj = cls->GetValue(cse.back()->callable->className,
|
|
"set" + std::get<std::string>(k));
|
|
TCallable *callable;
|
|
if (GetObjectHeap(obj, callable)) {
|
|
gc->BarrierEnd();
|
|
|
|
callable->Call(ls, {value});
|
|
gc->BarrierBegin();
|
|
} else {
|
|
cls->SetValue(cse.back()->callable->className,
|
|
std::get<std::string>(k), value);
|
|
}
|
|
}
|
|
}
|
|
|
|
stk->Push(gc, objhold);
|
|
|
|
gc->BarrierEnd();
|
|
return false;
|
|
}
|
|
bool InterperterThread::CreateArray(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
GCList ls(gc);
|
|
stk->Pop(ls);
|
|
return false;
|
|
}
|
|
bool InterperterThread::TryCatch(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<TException>(
|
|
ls, ex.what(), "RuntimeException")}));
|
|
} catch (VMException &ex) {
|
|
stk->Push(
|
|
gc, catchC->Call(ls, {TNativeObject::Create<TException>(
|
|
ls, ex.GetMessage(), "VMException")}));
|
|
} catch (VMByteCodeException &ex) {
|
|
stk->Push(gc, catchC->Call(ls, {ex.exception}));
|
|
} catch (std::exception &ex) {
|
|
stk->Push(gc,
|
|
catchC->Call(
|
|
ls, {TNativeObject::Create<TNativeException>(
|
|
ls, ex.what(), std::current_exception())}));
|
|
} catch (...) {
|
|
stk->Push(gc,
|
|
catchC->Call(ls, {TNativeObject::Create<TNativeException>(
|
|
ls, "<No Message>",
|
|
std::current_exception())}));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool InterperterThread::JumpConditional(std::shared_ptr<GC> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
auto stk = cse.back();
|
|
if (stk->ip + 4 <= stk->callable->closure->code.size()) {
|
|
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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
if (!cse.empty()) {
|
|
auto stk = cse.back();
|
|
std::vector<uint8_t> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
|
|
auto stk = cse.back();
|
|
|
|
gc->BarrierBegin();
|
|
GCList ls(gc);
|
|
std::vector<TCallable *> callable;
|
|
std::vector<uint8_t> &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> gc) {
|
|
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
|
|
|
|
auto stk = cse.back();
|
|
|
|
gc->BarrierBegin();
|
|
GCList ls(gc);
|
|
std::vector<TCallable *> 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> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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> gc) {
|
|
|
|
std::vector<CallStackEntry *> &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<THeapObject *> objs;
|
|
gc->Collect(objs);
|
|
for (auto &item : objs) {
|
|
delete item;
|
|
}
|
|
}
|
|
}
|
|
|
|
stk->mustReturn = false;
|
|
} catch (...) {
|
|
|
|
{
|
|
gc->BarrierBegin();
|
|
GCList ls(gc);
|
|
std::vector<TCallable *> 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<TCallable *> 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<TCallable *> 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> 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 *InterperterThread::Create(GCList *ls) {
|
|
return ls->Create<InterperterThread>();
|
|
}
|
|
CallStackEntry *CallStackEntry::Create(GCList &ls) {
|
|
return ls.Create<CallStackEntry>();
|
|
}
|
|
|
|
CallStackEntry *CallStackEntry::Create(GCList *ls) {
|
|
return ls->Create<CallStackEntry>();
|
|
}
|
|
void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure,
|
|
std::vector<TObject> 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
|