Added FS.MemoryFilesystem

This commit is contained in:
Mike Nolan 2025-01-03 05:54:27 -06:00
parent 82bf80ba06
commit f0a7c77134
16 changed files with 1105 additions and 991 deletions

4
.vscode/launch.json vendored
View File

@ -8,8 +8,8 @@
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/builds/linux/crosslang",
"args": [],
"program": "${workspaceFolder}/builds/linux/crossvm",
"args": ["builds/linux/out-1.0.0.0-prod.crvm"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],

View File

@ -109,6 +109,7 @@ src/vm/gc.cpp
src/vm/gclist.cpp
src/vm/vm.cpp
src/bitconverter.cpp
src/archive.cpp
)
if(CROSSLANG_ENABLE_SQLITE)
@ -163,37 +164,72 @@ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TessesCrossLangConfig.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang)
else()
if(CROSSLANG_ENABLE_SHARED)
install(TARGETS crosslang_shared
EXPORT TessesCrossLangTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()
endif()
if(CROSSLANG_ENABLE_BINARIES)
if(CROSSLANG_ENABLE_STATIC)
if(CROSSLANG_ENABLE_SHARED)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
add_executable(crossc src/crosslangcompiler.cpp)
add_executable(crossvm src/crosslangvm.cpp)
add_executable(crossint src/crosslanginterperter.cpp)
add_executable(crossdump src/crosslangdump.cpp)
add_executable(crosslang src/crosslang.cpp)
add_executable(crossarchiveextract src/crossarchiveextract.cpp)
add_executable(crossarchivecreate src/crossarchivecreate.cpp)
target_link_libraries(crossc PUBLIC crosslang_shared)
target_link_libraries(crossvm PUBLIC crosslang_shared)
target_link_libraries(crossint PUBLIC crosslang_shared)
target_link_libraries(crossdump PUBLIC crosslang_shared)
target_link_libraries(crosslang PUBLIC crosslang_shared)
target_link_libraries(crossarchiveextract PUBLIC crosslang_shared)
target_link_libraries(crossarchivecreate PUBLIC crosslang_shared)
elseif(CROSSLANG_ENABLE_STATIC)
add_executable(crossc src/crosslangcompiler.cpp)
add_executable(crossvm src/crosslangvm.cpp)
add_executable(crossint src/crosslanginterperter.cpp)
add_executable(crossdump src/crosslangdump.cpp)
add_executable(crosslang src/crosslang.cpp)
add_executable(crossarchiveextract src/crossarchiveextract.cpp)
add_executable(crossarchivecreate src/crossarchivecreate.cpp)
target_link_libraries(crossc PUBLIC crosslang_static)
target_link_libraries(crossvm PUBLIC crosslang_static)
target_link_libraries(crossint PUBLIC crosslang_static)
target_link_libraries(crossdump PUBLIC crosslang_static)
target_link_libraries(crosslang PUBLIC crosslang_static)
target_link_libraries(crossarchiveextract PUBLIC crosslang_static)
target_link_libraries(crossarchivecreate PUBLIC crosslang_static)
else()
add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_SOURCE})
add_executable(crossvm src/crosslangvm.cpp ${CROSSLANG_SOURCE})
add_executable(crossint src/crosslanginterperter.cpp ${CROSSLANG_SOURCE})
add_executable(crossdump src/crosslangdump.cpp ${CROSSLANG_SOURCE})
add_executable(crosslang src/crosslang.cpp ${CROSSLANG_SOURCE})
add_executable(crossarchiveextract src/crossarchiveextract.cpp ${CROSSLANG_SOURCE})
add_executable(crossarchivecreate src/crossarchivecreate.cpp ${CROSSLANG_SOURCE})
CROSSLANG_LINK_DEPS(crossc)
CROSSLANG_LINK_DEPS(crossvm)
CROSSLANG_LINK_DEPS(crossint)
CROSSLANG_LINK_DEPS(crosslang)
CROSSLANG_LINK_DEPS(crossdump)
CROSSLANG_LINK_DEPS(crossarchiveextract)
CROSSLANG_LINK_DEPS(crossarchivecreate)
endif()
install(TARGETS crossc DESTINATION bin)
install(TARGETS crossvm DESTINATION bin)
install(TARGETS crossint DESTINATION bin)
install(TARGETS crossdump DESTINATION bin)
install(TARGETS crosslang DESTINATION bin)
install(TARGETS crossarchiveextract DESTINATION bin)
install(TARGETS crossarchivecreate DESTINATION bin)
endif()
include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_CONTACT "Mike Nolan <tesses@tesses.net>")

View File

@ -3,3 +3,13 @@
include("${CMAKE_CURRENT_LIST_DIR}/TessesCrossLangTargets.cmake")
check_required_components(TessesCrossLang)
find_package(TessesFramework REQUIRED)
if(@CROSSLANG_ENABLE_SDL2@)
find_package(SDL2 REQUIRED)
find_package(SDL2_ttf REQUIRED)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube")
else()
find_package(SDL2_image REQUIRED)
endif()
endif()

View File

@ -232,6 +232,7 @@ namespace Tesses::CrossLang {
return true;
}
std::string ToString()
{
std::string str={};
@ -263,6 +264,9 @@ namespace Tesses::CrossLang {
};
void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name,TVMVersion version,std::string info);
std::pair<std::pair<std::string,TVMVersion>,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs);
@ -1162,19 +1166,42 @@ class GC {
bool BAnd(GC* gc);
bool ExecuteFunction(GC* gc);
bool ExecuteMethod(GC* gc);
void GetVariable(GC* gc);
void SetVariable(GC* gc);
bool GetVariable(GC* gc);
bool SetVariable(GC* gc);
bool GetField(GC* gc);
bool SetField(GC* gc);
bool GetArray(GC* gc);
bool SetArray(GC* gc);
void DeclareVariable(GC* gc);
void PushLong(GC* gc);
void PushDouble(GC* gc);
void PushChar(GC* gc);
void PushString(GC* gc);
void PushClosure(GC* gc,bool ownScope=true);
void PushResource(GC* gc);
bool DeclareVariable(GC* gc);
bool PushLong(GC* gc);
bool PushDouble(GC* gc);
bool PushChar(GC* gc);
bool PushString(GC* gc);
bool PushClosure(GC* gc);
bool PushScopelessClosure(GC* gc);
bool PushResource(GC* gc);
bool Illegal(GC* gc);
bool Throw(GC* gc);
bool Jump(GC* gc);
bool JumpConditional(GC* gc);
bool JumpUndefined(GC* gc);
bool Defer(GC* gc);
bool TryCatch(GC* gc);
bool Return(GC* gc);
bool ScopeBegin(GC* gc);
bool ScopeEnd(GC* gc);
bool ScopeEndTimes(GC* gc);
bool PushTrue(GC* gc);
bool PushFalse(GC* gc);
bool PushNull(GC* gc);
bool PushUndefined(GC* gc);
bool CreateDictionary(GC* gc);
bool CreateArray(GC* gc);
bool AppendList(GC* gc);
bool AppendDictionary(GC* gc);
bool Pop(GC* gc);
bool Dup(GC* gc);
bool Nop(GC* gc);
public:
static InterperterThread* Create(GCList* ls);
static InterperterThread* Create(GCList& ls);

291
src/archive.cpp Normal file
View File

@ -0,0 +1,291 @@
#include "CrossLang.hpp"
#include <iostream>
namespace Tesses::CrossLang
{
void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info)
{
static std::vector<uint8_t> error_message_byte_code = {
PUSHSTRING,
0,
0,
0,
2,
GETVARIABLE,
PUSHSTRING,
0,
0,
0,
3,
PUSHSTRING,
0,
0,
0,
4,
PUSHLONG,
0,
0,
0,
0,
0,
0,
0,
1,
CALLMETHOD,
RET
};
auto writeInt = [](Tesses::Framework::Streams::Stream* strm,uint32_t number)->void{
uint8_t buff[4];
BitConverter::FromUint32BE(buff[0],number);
strm->WriteBlock(buff,4);
};
auto writeStr = [&writeInt](Tesses::Framework::Streams::Stream* strm,std::string text)->void {
writeInt(strm,(uint32_t)text.size());
strm->WriteBlock((const uint8_t*)text.c_str(),text.size());
};
std::vector<std::string> strs;
strs.push_back(name);
strs.push_back(info);
strs.push_back("Console");
strs.push_back("WriteLine");
strs.push_back("You are trying to run a crvm archive, stop it you won't get anywhere!\nUse crossarchiveextract instead.");
std::vector<std::string> resources;
auto ensureResource = [&resources](std::string path)->uint32_t {
for(uint32_t i = 0; i < (uint32_t)resources.size(); i++)
{
if(resources[i] == path) return i;
}
uint32_t index = (uint32_t)resources.size();
resources.push_back(path);
return index;
};
auto ensureString = [&strs](std::string str)->uint32_t {
for(uint32_t i = 0; i < (uint32_t)strs.size(); i++)
{
if(strs[i] == str) return i;
}
uint32_t index = (uint32_t)strs.size();
strs.push_back(str);
return index;
};
Tesses::Framework::Streams::MemoryStream ms(true);
std::function<void(Tesses::Framework::Filesystem::VFSPath)> walkFS = [vfs,&ensureString,&ensureResource,&ms,&walkFS,&writeInt](Tesses::Framework::Filesystem::VFSPath path)->void {
if(vfs->DirectoryExists(path))
{
ms.WriteByte(1);
std::vector<std::string> paths;
for(auto item : vfs->EnumeratePaths(path))
{
if(!item.relative && item.path.size() == 1 && item.path[0] == "__resdir_tmp") continue;
if(vfs->DirectoryExists(item) || vfs->RegularFileExists(item))
paths.push_back(item.GetFileName());
}
writeInt(&ms,(uint32_t)paths.size());
for(auto item : paths)
{
writeInt(&ms,ensureString(item));
walkFS(path / item);
}
}
else if(vfs->RegularFileExists(path))
{
ms.WriteByte(0);
writeInt(&ms,ensureResource(path.ToString()));
}
};
walkFS(std::string("/"));
uint8_t main_header[18];
memcpy(main_header,"TCROSSVM",8);
TVMVersion rtVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
rtVersion.ToArray(main_header+8);
version.ToArray(main_header+13);
strm->WriteBlock(main_header,sizeof(main_header));
writeInt(strm,(uint32_t)(5+resources.size()));
strm->WriteBlock((const uint8_t*)"STRS",4);
uint32_t sz=4;
for(auto str : strs)
sz += (uint32_t)(4 + str.size());
writeInt(strm,sz);
writeInt(strm,(uint32_t)strs.size());
for(auto str : strs)
{
writeStr(strm,str);
}
strm->WriteBlock((const uint8_t*)"NAME",4);
writeInt(strm,4);
writeInt(strm,0);
strm->WriteBlock((const uint8_t*)"INFO",4);
writeInt(strm,4);
writeInt(strm,1);
strm->WriteBlock((const uint8_t*)"CHKS",4);
writeInt(strm,(uint32_t)(12+error_message_byte_code.size()));
writeInt(strm,1);
writeInt(strm,0);
writeInt(strm,(uint32_t)error_message_byte_code.size());
strm->WriteBlock(error_message_byte_code.data(),error_message_byte_code.size());
for(auto res : resources)
{
strm->WriteBlock((const uint8_t*)"RESO",4);
auto strm2 = vfs->OpenFile(res,"rb");
writeInt(strm,(uint32_t)strm2->GetLength());
strm2->CopyTo(strm);
delete strm2;
}
strm->WriteBlock((const uint8_t*)"ARCV",4);
writeInt(strm,(uint32_t)ms.GetLength());
ms.Seek(0,Tesses::Framework::Streams::SeekOrigin::Begin);
ms.CopyTo(strm);
}
std::pair<std::pair<std::string,TVMVersion>,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs)
{
auto ensure = [strm](uint8_t* buffer,size_t count)->void{
size_t read = strm->ReadBlock(buffer, count);
if(read < count) throw VMException("End of file, could not read " + std::to_string((int64_t)count) + " byte(s)., offset=" + std::to_string(strm->GetLength()));
};
auto ensureInt = [&ensure]()->uint32_t {
uint8_t buffer[4];
ensure(buffer,4);
return BitConverter::ToUint32BE(buffer[0]);
};
auto ensureStr = [&ensure,&ensureInt]()-> std::string {
auto len = ensureInt();
if(len == 0) return {};
std::string str={};
str.resize((size_t)len);
ensure((uint8_t*)str.data(),str.size());
return str;
};
std::vector<std::string> strs;
auto getStr = [&ensure,&ensureInt,&strs]()-> std::string {
auto index = ensureInt();
if(index > strs.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(strs.size()));
return strs[index];
};
uint8_t main_header[18];
ensure(main_header,sizeof(main_header));
if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image.");
TVMVersion version(main_header+8);
if(version.CompareToRuntime() == 1)
{
throw VMException("Runtime is too old.");
}
TVMVersion v2(main_header+13);
std::string name;
std::string info;
size_t _len = (size_t)ensureInt();
char table_name[4];
uint32_t resource_id = 0;
Tesses::Framework::Filesystem::VFSPath tmpDir("/__resdir_tmp");
vfs->CreateDirectory(tmpDir);
for(size_t i = 0;i < _len; i++)
{
ensure((uint8_t*)table_name,sizeof(table_name));
size_t tableLen = (size_t)ensureInt();
if(strncmp(table_name,"NAME",4) == 0)
{
name = getStr();
}
else if(strncmp(table_name,"INFO",4) == 0)
{
info = getStr();
}
else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed)
{
auto path = tmpDir /std::to_string(resource_id);
auto strm2 = vfs->OpenFile(path,"wb");
size_t read = 0;
size_t offset = 0;
uint8_t buff[1024];
do {
read = std::min(std::min(tableLen-offset,tableLen), sizeof(buff));
read = strm->Read(buff,read);
if(read > 0)
strm2->WriteBlock(buff,read);
offset+=read;
} while(read > 0);
delete strm2;
resource_id++;
}
else if(strncmp(table_name,"STRS",4) == 0) //strings
{
size_t strsLen = (size_t)ensureInt();
for(size_t j = 0;j < strsLen;j++)
{
strs.push_back(ensureStr());
}
}
else if(strncmp(table_name,"ARCV",4) == 0)
{
size_t offset = 0;
std::function<void(Tesses::Framework::Filesystem::VFSPath)> walkEntry = [strm,vfs,&getStr,&ensureInt,&tmpDir,&tableLen,&offset,&walkEntry](Tesses::Framework::Filesystem::VFSPath path)->void {
if(offset + 1 > tableLen) return;
uint8_t type = strm->ReadByte();
offset++;
if(type == 1)
{
//ISDIR
vfs->CreateDirectory(path);
if(offset + 4 > tableLen) return;
uint32_t count = ensureInt();
offset +=4;
for(uint32_t i = 0; i < count; i++)
{
if(offset + 4 > tableLen) return;
std::string name = getStr();
offset +=4;
walkEntry(path / name);
}
}
else if(type == 0)
{
if(offset + 4 > tableLen) return;
uint32_t index = ensureInt();
auto fSrc = tmpDir /std::to_string(index);
vfs->MoveFile(fSrc, path);
}
};
walkEntry(std::string("/"));
}
else
{
if(strm->CanSeek())
{
strm->Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current);
}
else{
uint8_t* buffer=new uint8_t[tableLen];
ensure(buffer,tableLen);
delete buffer;
}
}
}
vfs->DeleteDirectoryRecurse(tmpDir);
return std::pair<std::pair<std::string,TVMVersion>,std::string>(std::pair<std::string,TVMVersion>(name,v2),info);
}
}

View File

@ -0,0 +1,83 @@
#include <CrossLang.hpp>
#include <iostream>
using namespace Tesses::CrossLang;
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Streams;
void Help(const char* filename)
{
printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\n", filename);
printf("OPTIONS:\n");
printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -h, --help: Prints help\n");
printf("Options except for help have flag with arg like this: -F ARG\n");
exit(1);
}
int main(int argc, char** argv)
{
std::string name="out";
std::string info="{}";
TVMVersion version;
std::vector<std::string> args;
for(int i = 1; i < argc; i++)
{
if(strcmp(argv[i],"--help") == 0 || strcmp(argv[i],"-h")==0)
{
Help(argv[0]);
}
else if(strcmp(argv[i], "-i") == 0)
{
i++;
if(i < argc)
{
info = argv[i];
}
}
else if(strcmp(argv[i], "-n") == 0)
{
i++;
if(i < argc)
{
name = argv[i];
}
}
else if(strcmp(argv[i], "-v") == 0)
{
i++;
if(i < argc)
{
if(!TVMVersion::TryParse(argv[i],version))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
}
}
else {
args.push_back(argv[i]);
}
}
if(args.size() < 2) Help(argv[0]);
LocalFilesystem fs;
auto path = fs.SystemToVFSPath(args[0]);
fs.CreateDirectory(path);
SubdirFilesystem sdfs(&fs,path,false);
FILE* f = fopen(args[1].c_str(),"wb");
if(f == NULL)
{
printf("ERROR: could not open %s\n", args[1].c_str());
return 1;
}
FileStream strm(f,true,"wb",true);
CrossArchiveCreate(&sdfs,&strm,name,version,info);
return 0;
}

View File

@ -0,0 +1,34 @@
#include <CrossLang.hpp>
#include <iostream>
using namespace Tesses::CrossLang;
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Streams;
int main(int argc, char** argv)
{
if(argc < 3)
{
printf("USAGE: %s <archive.crvm> <dirasroot>\n", argv[0]);
return 1;
}
LocalFilesystem fs;
SubdirFilesystem sdfs(&fs,std::string(argv[2]),false);
FILE* f = fopen(argv[1],"rb");
if(f == NULL)
{
printf("ERROR: could not open %s\n", argv[1]);
return 1;
}
FileStream strm(f,true,"rb",true);
auto res = CrossArchiveExtract(&strm,&sdfs);
std::cout << "Crvm Name: " << res.first.first << std::endl;
std::cout << "Crvm Version: " << res.first.second.ToString() << std::endl;
std::cout << "Crvm Info: " << std::endl << res.second << std::endl;
return 0;
}

View File

@ -40,10 +40,7 @@ int main(int argc, char** argv)
std::string name="out";
std::string info="{}";
TVMVersion version;
if(argc < 2)
{
Help(argv[0]);
}
for(int i = 1; i < argc; i++)
{
@ -135,7 +132,10 @@ int main(int argc, char** argv)
source.push_back(argv[i]);
}
}
if(source.empty())
{
Help(argv[0]);
}
std::vector<LexToken> tokens;

View File

@ -17,8 +17,9 @@ int main(int argc, char** argv)
GCList ls(gc);
TRootEnvironment* env = TRootEnvironment::Create(ls, TDictionary::Create(ls));
Tesses::Framework::Filesystem::LocalFilesystem fs;
env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1]));
TStd::RegisterStd(&gc,env);
env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1]));
TList* args = TList::Create(ls);
for(int arg=1;arg<argc;arg++)
args->Add(std::string(argv[arg]));

View File

@ -19,557 +19,7 @@
namespace Tesses::CrossLang
{
#if defined(CROSSLANG_ENABLE_MBED)
static void my_debug(void *ctx, int level,
const char *file, int line,
const char *str)
{
((void) level);
fprintf(stderr, "%s:%04d: %s", file, line, str);
fflush(stderr);
}
class TlsClientStream {
GCList* ls;
TCallable* read;
TCallable* write;
TCallable* close;
TByteArray* readBuffer;
TByteArray* writeBuffer;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cachain;
static int strm_send(void* ctx,const unsigned char* buf,size_t len)
{
TlsClientStream* strm = static_cast<TlsClientStream*>(ctx);
strm->writeBuffer->data.resize(len);
memcpy(strm->writeBuffer->data.data(),buf,len);
auto res = strm->write->Call(*strm->ls,{strm->writeBuffer});
if(std::holds_alternative<int64_t>(res))
{
auto num = std::get<int64_t>(res);
return (int)num;
}
return -1;
}
static int strm_recv(void* ctx,unsigned char* buf,size_t len)
{
TlsClientStream* strm = static_cast<TlsClientStream*>(ctx);
strm->readBuffer->data.resize(len);
auto res = strm->read->Call(*strm->ls,{strm->readBuffer});
if(std::holds_alternative<int64_t>(res))
{
auto num = std::get<int64_t>(res);
if(num < 0) return (int)num;
size_t read = (size_t)num;
if(read > len) read = len;
memcpy(buf,strm->readBuffer->data.data(), read);
return read;
}
return -1;
//return (int)strm->Read((uint8_t*)buf,len);
}
public:
void Close()
{
close->Call(*ls,{});
}
bool success=false;
bool isDoneReading = false;
int64_t Read(uint8_t* buffer, size_t len)
{
if(isDoneReading) return 0;
int64_t r = (int64_t)mbedtls_ssl_read(&ssl,buffer,len);
if(r == 0) isDoneReading=true;
if(r == -30848)
{
isDoneReading = true;
return 0;
}
return r;
}
int64_t Write(uint8_t* buffer, size_t len)
{
return (int64_t)mbedtls_ssl_write(&ssl,buffer,len);
}
TlsClientStream(GC* gc,std::string domain,std::string chain,bool verify, TCallable* read, TCallable* write, TCallable* close)
{
ls = new GCList(gc);
ls->Add(read);
ls->Add(write);
ls->Add(close);
this->read = read;
this->write = write;
this->close = close;
readBuffer = TByteArray::Create(ls);
writeBuffer = TByteArray::Create(ls);
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_x509_crt_init(&cachain);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
const char* pers = "CrossLangTLS";
int ret=0;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = psa_crypto_init();
if (status != PSA_SUCCESS) {
mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
(int) status);
return;
}
#endif
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen(pers))) != 0)
{
printf("FAILED mbedtls_ctr_drbg_seed\n");
return;
}
if(ret != 0) { printf("FAILED mbedtls_x509_crt_parse cert %i\n",ret); return;}
ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) chain.c_str(),
chain.size()+1);
if(ret != 0) {printf("FAILED mbedtls_x509_crt_parse chain %i\n",ret); return;}
if((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
char buffer[100];
mbedtls_strerror(ret,buffer,sizeof(buffer));
printf("FAILED mbedtls_ssl_conf_defaults %s\n",buffer);
return;
}
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_dbg(&conf,my_debug,stdout);
/* #if defined(MBEDTLS_SSL_CACHE_C)
mbedtls_ssl_conf_session_cache(&conf, &cache,
mbedtls_ssl_cache_get,
mbedtls_ssl_cache_set);
#endif*/
mbedtls_ssl_conf_authmode(&conf, verify ? MBEDTLS_SSL_VERIFY_REQUIRED: MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL);
mbedtls_ssl_set_bio(&ssl, static_cast<void*>(this),strm_send,strm_recv, NULL);
if((ret=mbedtls_ssl_setup(&ssl,&conf) != 0))
{
printf("FAILED mbedtls_ssl_setup %i\n",ret);
return;
}
if((ret=mbedtls_ssl_set_hostname(&ssl,domain.c_str()) != 0))
{
printf("FAILED mbedtls_ssl_set_hostname %i\n",ret);
return;
}
if((ret = mbedtls_ssl_handshake(&ssl)) != 0)
{
char buffer[100];
mbedtls_strerror(ret,buffer,sizeof(buffer));
printf("FAILED mbedtls_ssl_handshake %s\n",buffer);
return;
}
uint32_t flags;
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
#if !defined(MBEDTLS_X509_REMOVE_INFO)
char vrfy_buf[512];
#endif
#if !defined(MBEDTLS_X509_REMOVE_INFO)
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
#endif
if(verify)
return;
}
success=true;
}
~TlsClientStream()
{
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
mbedtls_ssl_config_free(&conf);
#if defined(MBEDTLS_USE_PSA_CRYPTO)
mbedtls_psa_crypto_free();
#endif /* MBEDTLS_USE_PSA_CRYPTO */
delete ls;
}
};
class TlsServerStream {
GCList* ls;
TCallable* read;
TCallable* write;
TCallable* close;
TByteArray* readBuffer;
TByteArray* writeBuffer;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt srvcert;
mbedtls_x509_crt cachain;
mbedtls_pk_context pkey;
static int strm_send(void* ctx,const unsigned char* buf,size_t len)
{
TlsServerStream* strm = static_cast<TlsServerStream*>(ctx);
strm->writeBuffer->data.resize(len);
memcpy(strm->writeBuffer->data.data(),buf,len);
auto res = strm->write->Call(*strm->ls,{strm->writeBuffer});
if(std::holds_alternative<int64_t>(res))
{
auto num = std::get<int64_t>(res);
return (int)num;
}
return -1;
}
static int strm_recv(void* ctx,unsigned char* buf,size_t len)
{
TlsServerStream* strm = static_cast<TlsServerStream*>(ctx);
strm->readBuffer->data.resize(len);
auto res = strm->read->Call(*strm->ls,{strm->readBuffer});
if(std::holds_alternative<int64_t>(res))
{
auto num = std::get<int64_t>(res);
if(num < 0) return num;
size_t read = (size_t)num;
if(read > len) read = len;
memcpy(buf,strm->readBuffer->data.data(), read);
return read;
}
return -1;
//return (int)strm->Read((uint8_t*)buf,len);
}
public:
void Close()
{
close->Call(*ls,{});
}
bool success=false;
bool isDoneReading =false;
int64_t Read(uint8_t* buffer, size_t len)
{
if(isDoneReading) return 0;
int64_t r = (int64_t)mbedtls_ssl_read(&ssl,buffer,len);
if(r == 0) isDoneReading=true;
if(r == -30848)
{
isDoneReading = true;
return 0;
}
return r;
}
int64_t Write(uint8_t* buffer, size_t len)
{
return mbedtls_ssl_write(&ssl,buffer,len);
}
TlsServerStream(GC* gc,std::string cert, std::string chain, std::string privkey, TCallable* read, TCallable* write, TCallable* close)
{
ls = new GCList(gc);
ls->Add(read);
ls->Add(write);
ls->Add(close);
readBuffer = TByteArray::Create(ls);
writeBuffer = TByteArray::Create(ls);
this->read = read;
this->write = write;
this->close = close;
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_x509_crt_init(&srvcert);
mbedtls_x509_crt_init(&cachain);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
mbedtls_pk_init(&pkey);
const char* pers = "CrossLangTLS";
int ret=0;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = psa_crypto_init();
if (status != PSA_SUCCESS) {
mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
(int) status);
return;
}
#endif
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen(pers))) != 0)
{
printf("FAILED mbedtls_ctr_drbg_seed\n");
return;
}
ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) cert.c_str(),
cert.size()+1);
if(ret != 0) { printf("FAILED mbedtls_x509_crt_parse cert %i\n",ret); return;}
ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) chain.c_str(),
chain.size()+1);
if(ret != 0) {printf("FAILED mbedtls_x509_crt_parse chain %i\n",ret); return;}
ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) privkey.c_str(),
privkey.size()+1, NULL, 0);
if(ret != 0) {printf("FAILED mbedtls_pk_parse_key %i\n",ret); return;}
if((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
char buffer[100];
mbedtls_strerror(ret,buffer,sizeof(buffer));
printf("FAILED mbedtls_ssl_conf_defaults %s\n",buffer);
return;
}
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
/* #if defined(MBEDTLS_SSL_CACHE_C)
mbedtls_ssl_conf_session_cache(&conf, &cache,
mbedtls_ssl_cache_get,
mbedtls_ssl_cache_set);
#endif*/
mbedtls_ssl_conf_own_cert(&conf,&srvcert,&pkey);
mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL);
mbedtls_ssl_set_bio(&ssl, static_cast<void*>(this),strm_send,strm_recv, NULL);
if((ret=mbedtls_ssl_setup(&ssl,&conf) != 0))
{
printf("FAILED mbedtls_ssl_setup %i\n",ret);
return;
}
if((ret = mbedtls_ssl_handshake(&ssl)) != 0)
{
char buffer[100];
mbedtls_strerror(ret,buffer,sizeof(buffer));
printf("FAILED mbedtls_ssl_handshake %s\n",buffer);
return;
}
success=true;
}
~TlsServerStream()
{
mbedtls_x509_crt_free(&srvcert);
mbedtls_pk_free(&pkey);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
mbedtls_ssl_config_free(&conf);
#if defined(MBEDTLS_USE_PSA_CRYPTO)
mbedtls_psa_crypto_free();
#endif /* MBEDTLS_USE_PSA_CRYPTO */
delete ls;
}
};
static TObject Crypto_TlsClient(GCList& ls, std::vector<TObject> args)
{
//TlsServerStream(GC* gc,std::string domain, std::string chain, bool verify, TCallable* read, TCallable* write, TCallable* close)
if(args.size() == 6 && std::holds_alternative<std::string>(args[0]) && std::holds_alternative<std::string>(args[1]) && std::holds_alternative<bool>(args[2]) && std::holds_alternative<THeapObjectHolder>(args[3]) && std::holds_alternative<THeapObjectHolder>(args[4]) && std::holds_alternative<THeapObjectHolder>(args[5]))
{
std::string domain = std::get<std::string>(args[0]);
std::string chain = std::get<std::string>(args[1]);
bool verify = std::get<bool>(args[2]);
TCallable* read = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[3]).obj);
TCallable* write = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[4]).obj);
TCallable* close = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[5]).obj);
if(read != nullptr && write != nullptr && close != nullptr)
{
auto serverStream = new TlsClientStream(ls.GetGC(),domain,chain,verify,read,write,close);
if(!serverStream->success)
{
serverStream->Close();
delete serverStream;
return nullptr;
}
TNative* native = TNative::Create(ls,static_cast<void*>(serverStream),[](void* ptr)->void {
if(ptr == nullptr) return;
TlsClientStream* strm = static_cast<TlsClientStream*>(ptr);
strm->Close();
delete strm;
});
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("_native",native);
ls.GetGC()->BarrierEnd();
dict->DeclareFunction(ls.GetGC(),"Read","Read data from Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
size_t offset = (size_t)std::get<int64_t>(args2[1]);
size_t length = (size_t)std::get<int64_t>(args2[2]);
if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size()))
{
auto strm = static_cast<TlsClientStream*>(native->GetPointer());
return strm->Read(byteArray->data.data()+offset, length);
}
}
return Undefined();
});
dict->DeclareFunction(ls.GetGC(),"Write","Write data to Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
size_t offset = (size_t)std::get<int64_t>(args2[1]);
size_t length = (size_t)std::get<int64_t>(args2[2]);
if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size()))
{
auto strm = static_cast<TlsClientStream*>(native->GetPointer());
return strm->Write(byteArray->data.data()+offset, length);
}
}
return Undefined();
});
dict->DeclareFunction(ls.GetGC(),"Close","Close Tls Connection",{},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(!native->GetDestroyed())
{
native->Destroy();
}
return Undefined();
});
return dict;
}
}
return Undefined();
}
static TObject Crypto_TlsServer(GCList& ls, std::vector<TObject> args)
{
//TlsServerStream(GC* gc,std::string cert, std::string chain, std::string privkey, TCallable* read, TCallable* write, TCallable* close)
if(args.size() == 6 && std::holds_alternative<std::string>(args[0]) && std::holds_alternative<std::string>(args[1]) && std::holds_alternative<std::string>(args[2]) && std::holds_alternative<THeapObjectHolder>(args[3]) && std::holds_alternative<THeapObjectHolder>(args[4]) && std::holds_alternative<THeapObjectHolder>(args[5]))
{
std::string cert = std::get<std::string>(args[0]);
std::string chain = std::get<std::string>(args[1]);
std::string privkey = std::get<std::string>(args[2]);
TCallable* read = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[3]).obj);
TCallable* write = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[4]).obj);
TCallable* close = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[5]).obj);
if(read != nullptr && write != nullptr && close != nullptr)
{
auto serverStream = new TlsServerStream(ls.GetGC(),cert,chain,privkey,read,write,close);
if(!serverStream->success)
{
serverStream->Close();
delete serverStream;
return nullptr;
}
TNative* native = TNative::Create(ls,static_cast<void*>(serverStream),[](void* ptr)->void {
if(ptr == nullptr) return;
TlsServerStream* strm = static_cast<TlsServerStream*>(ptr);
strm->Close();
delete strm;
});
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("_native",native);
ls.GetGC()->BarrierEnd();
dict->DeclareFunction(ls.GetGC(),"Read","Read data from Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
size_t offset = (size_t)std::get<int64_t>(args2[1]);
size_t length = (size_t)std::get<int64_t>(args2[2]);
if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size()))
{
auto strm = static_cast<TlsServerStream*>(native->GetPointer());
return strm->Read(byteArray->data.data()+offset, length);
}
}
return Undefined();
});
dict->DeclareFunction(ls.GetGC(),"Write","Write data to Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
size_t offset = (size_t)std::get<int64_t>(args2[1]);
size_t length = (size_t)std::get<int64_t>(args2[2]);
if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size()))
{
auto strm = static_cast<TlsServerStream*>(native->GetPointer());
return strm->Write(byteArray->data.data()+offset, length);
}
}
return Undefined();
});
dict->DeclareFunction(ls.GetGC(),"Close","Close Tls Connection",{},[native](GCList& ls2, std::vector<TObject> args2)->TObject {
if(!native->GetDestroyed())
{
native->Destroy();
}
return Undefined();
});
return dict;
}
}
return Undefined();
}
static TObject Crypto_Sha1(GCList& ls, std::vector<TObject> args)
{
@ -750,6 +200,60 @@ namespace Tesses::CrossLang
return dict;
}
static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> args)
{
TByteArray* byteArray;
int64_t offset;
int64_t length;
if(GetArgumentHeap(args,0,byteArray) && GetArgument(args,1,offset) && GetArgument(args,2,length))
{
std::string str={};
size_t olen;
size_t off = (size_t)offset;
size_t len = (size_t)length;
len = std::min(std::min(byteArray->data.size(),len-off),len);
if(len > 0)
{
mbedtls_base64_encode((uint8_t*)str.data(), 0, &olen, byteArray->data.data()+offset,len);
str.resize(olen);
if(mbedtls_base64_encode((uint8_t*)str.data(), olen, &olen, byteArray->data.data()+offset,len)==0)
{
return str;
}
}
return "";
}
}
static TObject Crypto_Base64Decode(GCList& ls, std::vector<TObject> args)
{
std::string str;
if(GetArgument(args,0,str))
{
size_t olen;
TByteArray* bArray = TByteArray::Create(ls);
mbedtls_base64_decode(bArray->data.data(), 0, &olen, (const uint8_t*)str.data(),str.size());
str.resize(olen);
if(mbedtls_base64_decode(bArray->data.data(), olen, &olen, (const uint8_t*)str.data(),str.size())==0)
{
return str;
}
}
}
#endif
void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env)
{
@ -759,14 +263,10 @@ namespace Tesses::CrossLang
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
//dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},Json_Decode);
//dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},Json_Encode);
dict->DeclareFunction(gc, "Sha1","Sha1 Algorithm (needed for WebSocket handshake/BitTorrent etc) (don't use unless you have no other choice)",{},Crypto_Sha1);
dict->DeclareFunction(gc, "Sha256","Sha256 Algorithm",{"$is224"},Crypto_Sha256);
dict->DeclareFunction(gc, "Sha512","Sha512 Algorithm",{"$is384"},Crypto_Sha512);
dict->DeclareFunction(gc, "TlsClient", "Create TLS client for HTTPS client",{"domain","chain","verify","read","write","close"},Crypto_TlsClient);
dict->DeclareFunction(gc, "TlsServer", "Create TLS server for HTTPS server",{"cert","chain","privkey","read","write","close"},Crypto_TlsServer);
dict->DeclareFunction(gc, "Base64Encode","Sha512 Algorithm",{"data"},Crypto_Base64Encode);
gc->BarrierBegin();
env->DeclareVariable("Crypto", dict);
gc->BarrierEnd();

View File

@ -8,7 +8,6 @@ namespace Tesses::CrossLang
TDictionary* dict;
dict->items.begin();
if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0]))
{
auto item = dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(args[0]).obj);

View File

@ -35,6 +35,10 @@ namespace Tesses::CrossLang
}
return nullptr;
}
static TObject FS_CreateMemoryFilesystem(GCList& ls, std::vector<TObject> args)
{
return TVFSHeapObject::Create(ls, new Tesses::Framework::Filesystem::MemoryFilesystem());
}
static TObject FS_CreateFilesystem(GCList& ls, std::vector<TObject> args)
{
@ -71,6 +75,41 @@ namespace Tesses::CrossLang
}
return nullptr;
}
static TObject FS_CreateArchive(GCList& ls, std::vector<TObject> args)
{
TVFSHeapObject* vfs;
TStreamHeapObject* strm;
std::string name;
std::string version;
std::string info;
TVMVersion version2;
if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,3,version) && GetArgument(args,4,info) && TVMVersion::TryParse(version,version2))
{
CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info);
}
return nullptr;
}
static TObject FS_ExtractArchive(GCList& ls, std::vector<TObject> args)
{
TVFSHeapObject* vfs;
TStreamHeapObject* strm;
if(GetArgumentHeap(args,0,strm) && GetArgumentHeap(args,1,vfs))
{
auto res = CrossArchiveExtract(strm->stream,vfs->vfs);
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Name",res.first.first);
dict->SetValue("Version",res.first.second.ToString());
dict->SetValue("Info",res.second);
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
void TStd::RegisterIO(GC* gc,TRootEnvironment* env,bool enableLocalFilesystem)
{
@ -93,6 +132,10 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, FS_MemoryStream);
dict->DeclareFunction(gc, "CreateStream","Create stream", {"strm"},FS_CreateStream);
dict->DeclareFunction(gc, "CreateFilesystem","Create filesystem", {"fs"},FS_CreateFilesystem);
dict->DeclareFunction(gc, "CreateMemoryFilesystem","Create in memory filesystem", {},FS_CreateMemoryFilesystem);
dict->DeclareFunction(gc, "CreateArchive", "Create a crvm archive",{"fs","strm","name","version","info"},FS_CreateArchive);
dict->DeclareFunction(gc,"ExtractArchive", "Extract a crvm archive",{"strm","vfs"},FS_ExtractArchive);
env->DeclareVariable("FS", dict);
gc->BarrierEnd();
}

View File

@ -12,6 +12,31 @@ namespace Tesses::CrossLang
{
#if defined(CROSSLANG_ENABLE_JSON)
static bool IsValidForJson(TObject v)
{
if(std::holds_alternative<std::nullptr_t>(v)) return true;
if(std::holds_alternative<int64_t>(v)) return true;
if(std::holds_alternative<double>(v)) return true;
if(std::holds_alternative<bool>(v)) return true;
if(std::holds_alternative<std::string>(v)) return true;
if(std::holds_alternative<THeapObjectHolder>(v))
{
auto res = std::get<THeapObjectHolder>(v);
auto ls = dynamic_cast<TList*>(res.obj);
auto dict = dynamic_cast<TDictionary*>(res.obj);
if(ls != nullptr) return true;
if(dict != nullptr) return true;
}
return false;
}
static json_t* JsonSerialize(TObject v)
{
if(std::holds_alternative<std::nullptr_t>(v)) return json_null();
@ -34,7 +59,9 @@ namespace Tesses::CrossLang
json_t* items=json_array();
for(int64_t i = 0; i < ls->Count(); i++)
{
json_array_append_new(items,JsonSerialize(ls->Get(i)));
auto val = ls->Get(i);
if(IsValidForJson(val))
json_array_append_new(items,JsonSerialize(val));
}
return items;
}
@ -44,6 +71,7 @@ namespace Tesses::CrossLang
json_t* obj = json_object();
for(auto item : dict->items)
{
if(IsValidForJson(item.second))
json_object_setn_new(obj, item.first.c_str(), item.first.size(),JsonSerialize(item.second));
}
return obj;

View File

@ -329,6 +329,14 @@ namespace Tesses::CrossLang
}
return Undefined();
}
static TObject Net_HtmlEncode(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 1 && std::holds_alternative<std::string>(args[0]))
{
return HttpUtils::HtmlEncode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject Net_UrlEncode(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 1 && std::holds_alternative<std::string>(args[0]))
@ -530,6 +538,8 @@ namespace Tesses::CrossLang
TDictionary* dict = TDictionary::Create(ls);
TDictionary* http = TDictionary::Create(ls);
http->DeclareFunction(gc, "HtmlEncode","Html encode",{"param"}, Net_HtmlEncode);
http->DeclareFunction(gc, "UrlEncode","Url encode query param",{"param"}, Net_UrlEncode);
http->DeclareFunction(gc, "UrlDecode","Url decode query param",{"param"}, Net_UrlDecode);
http->DeclareFunction(gc, "UrlPathEncode","Url encode path",{"path"}, Net_UrlPathEncode);

View File

@ -80,6 +80,14 @@ namespace Tesses::CrossLang {
#define TVM_HANDLER(hndl) if(hndl(gc)) goto execute
typedef bool (InterperterThread::*opcode)(GC* gc);
bool InterperterThread::InvokeTwo(GCList& ls, TObject fn, TObject left, TObject right)
{
if(std::holds_alternative<THeapObjectHolder>(fn))
@ -3146,6 +3154,20 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, r);
return false;
}
if(key == "Length")
{
int64_t r = strm->stream != nullptr ? strm->stream->GetLength() : 0;
cse.back()->Push(gc, r);
return false;
}
if(key == "Position")
{
int64_t r = strm->stream != nullptr ? strm->stream->GetPosition() : 0;
cse.back()->Push(gc, r);
return false;
}
cse.back()->Push(gc, nullptr);
@ -3337,7 +3359,7 @@ namespace Tesses::CrossLang {
return false;
}
void InterperterThread::GetVariable(GC* gc)
bool InterperterThread::GetVariable(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
if(!cse.empty())
@ -3357,8 +3379,9 @@ namespace Tesses::CrossLang {
throw VMException("[GETVARIABLE] Can't pop string.");
}
}
return false;
}
void InterperterThread::SetVariable(GC* gc)
bool InterperterThread::SetVariable(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
if(!cse.empty())
@ -3379,8 +3402,9 @@ namespace Tesses::CrossLang {
throw VMException("[SETVARIABLE] Can't pop string.");
}
}
return false;
}
void InterperterThread::DeclareVariable(GC* gc)
bool InterperterThread::DeclareVariable(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
if(!cse.empty())
@ -3402,10 +3426,11 @@ namespace Tesses::CrossLang {
throw VMException("[DECLAREVARIABLE] Can't pop string.");
}
}
return false;
}
void InterperterThread::PushResource(GC* gc)
bool InterperterThread::PushResource(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
if(!cse.empty())
@ -3432,154 +3457,193 @@ namespace Tesses::CrossLang {
throw VMException("Can't read chunk.");
}
}
return false;
}
void InterperterThread::PushClosure(GC* gc,bool ownScope)
bool InterperterThread::Throw(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;
GCList ls(gc);
auto _res2 = cse.back()->Pop(ls);
gc->BarrierBegin();
GCList ls(gc);
TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,ownScope);
stk->Push(gc,closure);
gc->BarrierEnd();
}
if(!std::holds_alternative<Undefined>(_res2))
{
throw VMByteCodeException(gc,_res2);
}
return false;
}
bool InterperterThread::JumpUndefined(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
{
throw VMException("Can't read chunk.");
}
stk->Push(gc,_res2);
}
else
throw VMException("Can't read jmpundefined pc.");
return false;
}
void InterperterThread::PushString(GC* gc)
bool InterperterThread::Jump(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;
}
}
}
auto stk = cse.back();
void InterperterThread::PushLong(GC* gc)
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(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;
}
}
auto stk = cse.back();
stk->Push(gc,nullptr);
return false;
}
void InterperterThread::PushChar(GC* gc)
bool InterperterThread::PushUndefined(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;
}
}
auto stk = cse.back();
stk->Push(gc,Undefined());
return false;
}
void InterperterThread::PushDouble(GC* gc)
bool InterperterThread::PushFalse(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;
}
}
auto stk = cse.back();
stk->Push(gc,false);
return false;
}
void InterperterThread::Execute(GC* gc)
bool InterperterThread::PushTrue(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
execute:
stk->Push(gc,true);
return false;
}
bool InterperterThread::CreateDictionary(GC* gc)
{
if(!cse.empty())
{
auto stk = cse.back();
try{
while(stk->ip < 0xFFFFFFFF && stk->ip < stk->callable->closure->code.size())
{
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(GC* gc)
{
return false;
}
bool InterperterThread::AppendList(GC* gc)
{
uint32_t ip = stk->ip;
stk->ip = ip + 1;
switch(stk->callable->closure->code[ip])
{
case JMP:
{
if(stk->ip + 4 <= stk->callable->closure->code.size())
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))
{
uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]);
stk->ip = n;
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));
}
}*/
}
else
throw VMException("Can't read jmp pc.");
}
break;
case JMPC:
{
if(stk->ip + 4 <= stk->callable->closure->code.size())
stk->Push(gc, objhold);
gc->BarrierEnd();
return false;
}
bool InterperterThread::AppendDictionary(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))
{
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;
auto dict= dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(objhold).obj);
if(dict != nullptr)
{
dict->SetValue(std::get<std::string>(k), value);
}
}
else
throw VMException("Can't read jmpc pc.");
}
break;
case TRYCATCH:
{
stk->Push(gc, objhold);
gc->BarrierEnd();
return false;
}
bool InterperterThread::CreateArray(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(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(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);
@ -3621,178 +3685,214 @@ namespace Tesses::CrossLang {
stk->Push(gc, catchC->Call(ls,{dict}));
}
}
}
break;
case THROW:
{
return false;
}
bool InterperterThread::JumpConditional(GC* gc)
{
GCList ls2(gc);
auto _res2 = stk->Pop(ls2);
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]);
if(!std::holds_alternative<Undefined>(_res2))
{
throw VMByteCodeException(gc,_res2);
}
}
break;
case JMPUNDEFINED:
{
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);
stk->ip = stk->ip + 4;
if(std::holds_alternative<Undefined>(_res2))
stk->ip = n;
else
stk->Push(gc,_res2);
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 jmpundefined pc.");
}
break;
case ADD:
TVM_HANDLER(Add);
break;
case SUB:
TVM_HANDLER(Sub);
break;
case TIMES:
TVM_HANDLER(Times);
break;
case DIVIDE:
TVM_HANDLER(Divide);
break;
case MODULO:
TVM_HANDLER(Mod);
break;
case LEFTSHIFT:
TVM_HANDLER(LShift);
break;
case RIGHTSHIFT:
TVM_HANDLER(RShift);
break;
case LESSTHAN:
TVM_HANDLER(Lt);
break;
case LESSTHANEQ:
TVM_HANDLER(Lte);
break;
case GREATERTHAN:
TVM_HANDLER(Gt);
break;
case GREATERTHANEQ:
TVM_HANDLER(Gte);
break;
case NEQ:
TVM_HANDLER(NEq);
break;
case EQ:
TVM_HANDLER(Eq);
break;
case NEGATIVE:
TVM_HANDLER(Neg);
break;
case BITWISEOR:
TVM_HANDLER(BOr);
break;
case BITWISEAND:
TVM_HANDLER(BAnd);
break;
case BITWISENOT:
TVM_HANDLER(BNot);
break;
case NOT:
TVM_HANDLER(LNot);
break;
case XOR:
TVM_HANDLER(XOr);
break;
case CALLFUNCTION:
TVM_HANDLER(ExecuteFunction);
break;
case CALLMETHOD:
TVM_HANDLER(ExecuteMethod);
break;
case GETVARIABLE:
GetVariable(gc);
break;
case SETVARIABLE:
SetVariable(gc);
break;
case GETFIELD:
TVM_HANDLER(GetField);
break;
case SETFIELD:
TVM_HANDLER(SetField);
break;
case DECLAREVARIABLE:
DeclareVariable(gc);
break;
case PUSHRESOURCE:
PushResource(gc);
break;
case PUSHCLOSURE:
PushClosure(gc);
break;
case PUSHSCOPELESSCLOSURE:
PushClosure(gc,false);
break;
case PUSHLONG:
PushLong(gc);
break;
case PUSHDOUBLE:
PushDouble(gc);
break;
case PUSHSTRING:
PushString(gc);
break;
case PUSHCHAR:
PushChar(gc);
break;
case SCOPEBEGIN:
{
}
else
throw VMException("Can't read jmpc pc.");
return false;
}
bool InterperterThread::PushClosure(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);
stk->Push(gc,closure);
gc->BarrierEnd();
}
else
{
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::PushScopelessClosure(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);
stk->Push(gc,closure);
gc->BarrierEnd();
}
else
{
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::PushString(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(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(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(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(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(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(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();
}
break;
case SCOPEEND:
{
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();
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(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
for(auto item : callable)
{
GCList ls2(gc);
item->Call(ls2,{});
}
auto stk = cse.back();
GCList ls(gc);
auto res = stk->Pop(ls);
stk->Push(gc,res);
stk->Push(gc,res);
}
break;
case SCOPEENDTIMES:
{
gc->BarrierBegin();
return false;
}
bool InterperterThread::ScopeEndTimes(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;
@ -3818,130 +3918,79 @@ namespace Tesses::CrossLang {
GCList ls2(gc);
item->Call(ls2,{});
}
}
break;
case PUSHFALSE:
{
GCList ls(gc);
stk->Push(gc,false);
}
break;
case PUSHTRUE:
{
GCList ls(gc);
stk->Push(gc,true);
}
break;
case PUSHNULL:
{
GCList ls(gc);
stk->Push(gc,nullptr);
}
break;
case PUSHUNDEFINED:
{
GCList ls(gc);
stk->Push(gc,Undefined());
}
break;
case CREATEDICTIONARY:
{
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
stk->Push(gc,dict);
}
break;
case POP:
{
GCList ls(gc);
stk->Pop(ls);
}
break;
case CREATEARRAY:
{
GCList ls(gc);
TList* myList = TList::Create(ls);
stk->Push(gc,myList);
}
break;
return false;
}
bool InterperterThread::ScopeEnd(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
case APPENDLIST:
{
GCList ls(gc);
gc->BarrierBegin();
auto obj = stk->Pop(ls);
auto objhold= stk->Pop(ls);
if(std::holds_alternative<THeapObjectHolder>(objhold))
GCList ls(gc);
std::vector<TCallable*> callable;
if(!stk->env->defers.empty())
{
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));
}
}*/
ls.Add(stk->env);
callable.insert(callable.end(), stk->env->defers.begin(),stk->env->defers.end());
}
stk->Push(gc, objhold);
stk->scopes--;
stk->env = stk->env->GetParentEnvironment();
gc->BarrierEnd();
}
break;
case APPENDDICT:
{
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))
for(auto item : callable)
{
auto dict= dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(objhold).obj);
if(dict != nullptr)
{
dict->SetValue(std::get<std::string>(k), value);
}
GCList ls2(gc);
item->Call(ls2,{});
}
stk->Push(gc, objhold);
return false;
}
bool InterperterThread::Illegal(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(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
#define VM_OPCODE_TABLE_INLINE
#include "vm_opcode_table.h"
#undef VM_OPCODE_TABLE_INLINE
execute:
if(!cse.empty())
{
auto stk = cse.back();
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;
gc->BarrierEnd();
}
break;
case NOP:
//this does nothing
break;
case RET:
stk->ip = (uint32_t)stk->callable->closure->code.size();
break;
case DEFER:
{
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();
}
break;
default:
{
char chr[3];
snprintf(chr,3,"%02X",stk->callable->closure->code[ip]);
throw VMException("Illegal instruction: 0x" + std::string(chr) + ".");
}
}
if(gc->UsingNullThreads()) gc->Collect();

3
src/vm/vm_opcode_table.h Normal file

File diff suppressed because one or more lines are too long