Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
2f20b18
Add API to distinguish between Integer and Floating
yqs112358 Jun 15, 2021
ad30dfe
Fix Lua's isArray and getKind
yqs112358 Jul 20, 2021
f26fce3
Fix a bug about stack
yqs112358 Jul 20, 2021
0c944c5
Fix bugs
yqs112358 Jul 20, 2021
3379134
update test lib
LanderlYoung Dec 18, 2021
2ef15e5
Fix typo in QjsLocalReference.cc
jrpat Feb 23, 2022
db133da
don't erase the current value of SCRIPTX_BACKEND
jrpat Mar 2, 2022
8560994
Fix typo: destory -> destroy
Jaciezyt Jul 15, 2022
9c4a496
Merge pull request #1 from yqs112358/feature/bugfix-of-lua-array
yqs112358 Jul 31, 2022
00511b1
Fix old wrong code from PR
yqs112358 Jul 31, 2022
607adfd
Fix lua crash
yqs112358 Jul 31, 2022
d843347
Merge branch 'Tencent:main' into python
Aug 1, 2022
16758f5
add eval and many basic things
Aug 1, 2022
88412db
新增类注册,函数注册,类函数注册
Aug 2, 2022
3512265
新增prop和static
Aug 3, 2022
a230276
修复eval
Aug 3, 2022
4c3a817
fix Global and Weak
Aug 4, 2022
a65d835
Fork TestLibs from Tencent
yqs112358 Aug 4, 2022
6124393
change devops unit test to python backend
yqs112358 Aug 4, 2022
8def40d
add getScriptEngine
yqs112358 Aug 4, 2022
97b06d2
fix
Aug 4, 2022
0026359
fix Native
Aug 4, 2022
a4e9163
Small fix about Global ref
yqs112358 Aug 5, 2022
289595f
add Exception Translate
Aug 5, 2022
3cbbfd3
Fix for unittest devops
yqs112358 Aug 5, 2022
0571bba
Update unit_tests.yml
yqs112358 Aug 5, 2022
8fe38f2
add loadFile to engine (first step)
yqs112358 Aug 5, 2022
79dc32f
Merge branch 'Add-LoadFile' into python
yqs112358 Aug 5, 2022
5f633a7
Add loadFile for python backend
yqs112358 Aug 5, 2022
21d26fe
Polish PyEngine
Aug 6, 2022
ba0c42a
tmp
Aug 6, 2022
ab369d0
Try to fix python GIL scope
yqs112358 Aug 7, 2022
3312681
Fix GIL problem
yqs112358 Aug 7, 2022
85b2ad7
tmp
Aug 7, 2022
7ec4332
Fix exception deadlock
yqs112358 Aug 7, 2022
c1ceb65
Fix Scope for multi-instance GIL dead-lock
yqs112358 Aug 8, 2022
06c4836
Fix comment
yqs112358 Aug 8, 2022
024c2cc
modified: backend/Python/PyEngine.cc
Aug 8, 2022
0cbc9c4
Remove pybind11
Aug 8, 2022
f408b16
Add Class register and construct
Aug 8, 2022
a72e24a
Revert "modified: backend/Python/PyEngine.cc"
yqs112358 Aug 9, 2022
d23cc07
tmp
Aug 9, 2022
6958a48
Function warpper
Aug 9, 2022
03d2437
Fix a bug
Aug 9, 2022
35e4d53
Fix getGlobalDict crash
yqs112358 Aug 9, 2022
5be0aeb
warpFunction新增参数
Aug 10, 2022
48a59ae
Merge pull request #1 from LiteLDev/python-try-to-remove-bind11
Aug 10, 2022
a992b73
fix static function register & other small problems
yqs112358 Aug 22, 2022
0b1a8ed
All is fileinput
Aug 22, 2022
dde9bff
Merge branch 'python-try-to-remove-bind11' of https://github.com/Lite…
Aug 22, 2022
26e2593
debug version
Aug 22, 2022
91650c9
fix ref count
Aug 22, 2022
f1651e0
picture a cake
Aug 22, 2022
df3b5a3
picture a cake 2
Aug 23, 2022
1f925a3
fix problem of getGlobalDict
yqs112358 Aug 23, 2022
891c2cf
Fix a reference count problem
yqs112358 Aug 23, 2022
4fbd57c
picture a cake 3
Aug 23, 2022
d8f10ef
cake finishied!!!!!!!!!!
Aug 23, 2022
9eea0b1
Merge branch 'python-try-to-remove-bind11' into python
yqs112358 Aug 23, 2022
916be0c
fix static property
Aug 23, 2022
f5de7a4
Merge pull request #2 from LiteLDev/python
Aug 23, 2022
813a8f2
Finish exception system of python backend
yqs112358 Aug 24, 2022
ed12abf
Fix a global reference bug
yqs112358 Aug 24, 2022
dc61d15
Fix a memory leak
Aug 24, 2022
13d7906
better format of traceback
yqs112358 Aug 24, 2022
fa7f66e
Add two impl
Aug 24, 2022
8f6b5af
Polish code
Aug 24, 2022
f591ce2
New py_interop
Aug 24, 2022
86ad84d
New py_interop
Aug 24, 2022
80502df
Fix Weak
Aug 24, 2022
338f4ca
Fix memory leak
Aug 24, 2022
451a83a
Fix alllllllllllllllllll memory leak!!!!
Aug 24, 2022
1e9021a
tmp
Aug 24, 2022
a182f9b
Add namespace support
Aug 24, 2022
bb62c86
Fix isInstanceOf
Aug 24, 2022
58bf8ab
Merge pull request #3 from LiteLDev/python
Aug 24, 2022
ffc1815
pass basic multi-thread test & more work need to do
yqs112358 Aug 24, 2022
14df895
change oldThreadStateStack_ to TLS
yqs112358 Aug 25, 2022
3c04c0f
Fix GIL & thread state in multi-thread env thoroughly
yqs112358 Aug 25, 2022
3555cc4
Fix comment
yqs112358 Aug 25, 2022
6616800
avoid exit not-my-managed engine
yqs112358 Aug 25, 2022
46b98e4
Add module
Aug 25, 2022
25a8970
Fix destroy engine
yqs112358 Aug 25, 2022
3e3c682
Merge branch 'fix-for-unit-test' of https://github.com/LiteLDev/Scrip…
yqs112358 Aug 25, 2022
b144a5c
Fix GIL & thread state in PyEngine creation
yqs112358 Aug 25, 2022
94e544d
disable Py_EndInterpreter temporarily to fix it later
yqs112358 Aug 25, 2022
4b3002d
Fix Global Local Weak
Aug 25, 2022
affbbfc
Fix Local<Value> constructor
Aug 25, 2022
449b57b
Add code modification for python
Aug 29, 2022
a68c915
Fix exception crash bug
yqs112358 Aug 29, 2022
391e09f
Fix eval expression check (temp fix)
yqs112358 Aug 29, 2022
af79350
Fix an string error
Aug 29, 2022
df7164b
Merge branch 'fix-for-unit-test' of https://github.com/LiteLDev/Scrip…
Aug 29, 2022
412343d
add document for python
yqs112358 Aug 29, 2022
a26ca8b
Fix Array::set
Aug 29, 2022
a43e2a1
Merge branch 'fix-for-unit-test' of https://github.com/LiteLDev/Scrip…
Aug 29, 2022
4a176d2
Fix isByteBuffer
Aug 29, 2022
7dc7049
Fix type judgement
Aug 29, 2022
eb23dea
Fix unsupported
Aug 29, 2022
58be8b6
Polish the namespace support
Aug 30, 2022
246c577
Fix namespace waining
Aug 30, 2022
3f460a8
Modify class register
Aug 31, 2022
de7c2b0
Uncompeleted code
Sep 1, 2022
5cfcb76
Python warp
Sep 2, 2022
51ceecf
Merge pull request #3 from LiteLDev/fix-for-unit-test
Sep 2, 2022
b97a7f3
delete incRef and decRef
Sep 3, 2022
32733e6
Fix static property
Sep 3, 2022
c3d1faa
Polish warp code
Sep 3, 2022
35a61bd
Merge pull request #4 from LiteLDev/python
Sep 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
strategy:
fail-fast: false
matrix:
backends: [ V8, JavaScriptCore, Lua, Empty ]
backends: [ V8, JavaScriptCore, Lua, Python, Empty ]
build_type:
- Debug
- Release
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ set(SCRIPTX_BACKEND_LIST
)

# set options, choose which ScriptX Backend to use, V8 or JSC or etc...
set(SCRIPTX_BACKEND "" CACHE STRING "choose which ScriptX Backend(Implementation) to use, V8 or JavaScriptCore or etc...")
set(SCRIPTX_BACKEND "${SCRIPTX_BACKEND}" CACHE STRING "choose which ScriptX Backend(Implementation) to use, V8 or JavaScriptCore or etc...")
set_property(CACHE SCRIPTX_BACKEND PROPERTY STRINGS "${SCRIPTX_BACKEND_LIST}")
option(SCRIPTX_NO_EXCEPTION_ON_BIND_FUNCTION "don't throw exception on defineClass generated bound function/get/set, return null & log instead. default to OFF" OFF)
option(SCRIPTX_FEATURE_INSPECTOR "enable inspector feature, default to OFF" OFF)
Expand Down Expand Up @@ -177,4 +177,4 @@ message(STATUS "Configuring ScriptX using backend ${SCRIPTX_BACKEND}.")
message(STATUS "Configuring ScriptX option SCRIPTX_NO_EXCEPTION_ON_BIND_FUNCTION ${SCRIPTX_NO_EXCEPTION_ON_BIND_FUNCTION}.")
message(STATUS "Configuring ScriptX feature SCRIPTX_FEATURE_INSPECTOR ${SCRIPTX_FEATURE_INSPECTOR}.")

include(${SCRIPTX_DIR}/docs/doxygen/CMakeLists.txt)
include(${SCRIPTX_DIR}/docs/doxygen/CMakeLists.txt)
4 changes: 2 additions & 2 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ ScriptX通过一系列的技术手段实现了脚本的异常和C++异常相互

ScriptX 设计的时候充分考虑到API的易用性,包括操作友好简单,不易出错,错误信息明显,便于定位问题等。在这样的指导思想之下ScriptX做了很多原生引擎做不了的事情。

比如:V8在destory的时候是不执行GC的,导致很多绑定的native类不能释放。ScriptX做了额外的逻辑处理这个情况。
比如:V8在destroy的时候是不执行GC的,导致很多绑定的native类不能释放。ScriptX做了额外的逻辑处理这个情况。

V8和JSCore要求在finalize回调中不能调用ScriptX的其他API,否则会crash,这也导致代码逻辑很难实现。ScriptX借助MessageQueue完美规避这个问题。

V8和JSCore的全局引用都必须在engine destory之前全部释放掉,否则就会引起crash、不能destory等问题。ScriptX则保证在Engine destory的时候主动reset所有 Global / Weak 引用。
V8和JSCore的全局引用都必须在engine destroy之前全部释放掉,否则就会引起crash、不能destroy等问题。ScriptX则保证在Engine destroy的时候主动reset所有 Global / Weak 引用。

## 6. 简单高效的绑定API

Expand Down
22 changes: 22 additions & 0 deletions backend/JavaScriptCore/JscEngine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "../../src/Native.hpp"
#include "JscEngine.hpp"
#include "JscHelper.h"
#include "../../src/utils/Helper.hpp"

namespace script::jsc_backend {

Expand Down Expand Up @@ -177,6 +178,27 @@ script::Local<script::Value> JscEngine::eval(const script::Local<script::String>
return eval(script, {});
}

Local<Value> JscEngine::loadFile(const Local<String>& scriptFile) {
if(scriptFile.toString().empty())
throw Exception("script file no found");
Local<Value> content = internal::readAllFileContent(scriptFile);
if(content.isNull())
throw Exception("can't load script file");

std::string sourceFilePath = scriptFile.toString();
std::size_t pathSymbol = sourceFilePath.rfind("/");
if(pathSymbol != -1)
sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
else
{
pathSymbol = sourceFilePath.rfind("\\");
if(pathSymbol != -1)
sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
}
Local<String> sourceFileName = String::newString(sourceFilePath);
return eval(content.asString(), sourceFileName);
}

std::shared_ptr<utils::MessageQueue> JscEngine::messageQueue() { return messageQueue_; }

void JscEngine::gc() {
Expand Down
2 changes: 2 additions & 0 deletions backend/JavaScriptCore/JscEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class JscEngine : public ::script::ScriptEngine {
Local<Value> eval(const Local<String>& script) override;
using ScriptEngine::eval;

Local<Value> loadFile(const Local<String>& scriptFile) override;

std::shared_ptr<utils::MessageQueue> messageQueue() override;

void gc() override;
Expand Down
22 changes: 22 additions & 0 deletions backend/Lua/LuaEngine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "LuaHelper.hpp"
#include "LuaReference.hpp"
#include "LuaScope.hpp"
#include "../../src/utils/Helper.hpp"

// ref https://www.lua.org/manual/5.1/manual.html
// https://www.lua.org/wshop14/Zykov.pdf
Expand Down Expand Up @@ -259,6 +260,27 @@ Local<Value> LuaEngine::eval(const Local<String>& script, const Local<Value>& so
return lua_backend::callFunction({}, {}, 0, nullptr);
}

Local<Value> LuaEngine::loadFile(const Local<String>& scriptFile) {
if(scriptFile.toString().empty())
throw Exception("script file no found");
Local<Value> content = internal::readAllFileContent(scriptFile);
if(content.isNull())
throw Exception("can't load script file");

std::string sourceFilePath = scriptFile.toString();
std::size_t pathSymbol = sourceFilePath.rfind("/");
if(pathSymbol != -1)
sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
else
{
pathSymbol = sourceFilePath.rfind("\\");
if(pathSymbol != -1)
sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
}
Local<String> sourceFileName = String::newString(sourceFilePath);
return eval(content.asString(), sourceFileName);
}

Arguments LuaEngine::makeArguments(LuaEngine* engine, int stackBase, size_t paramCount,
bool isInstanceFunc) {
lua_backend::ArgumentsData argumentsData{engine, stackBase, paramCount, isInstanceFunc};
Expand Down
2 changes: 2 additions & 0 deletions backend/Lua/LuaEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class LuaEngine : public ScriptEngine {
Local<Value> eval(const Local<String>& script) override;
using ScriptEngine::eval;

Local<Value> loadFile(const Local<String>& scriptFile) override;

std::shared_ptr<utils::MessageQueue> messageQueue() override;

void gc() override;
Expand Down
37 changes: 33 additions & 4 deletions backend/Lua/LuaLocalReference.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,28 @@ void ensureNonnull(int index) {
throw Exception("NullPointerException");
}

bool judgeIsArray(int index)
{
auto lua = currentLua();
int currectArrIndex = 0;

lua_pushnil(lua);

while (lua_next(lua, index))
{
// Copy current key and judge it's type
lua_pushvalue(lua, -2);
if(!lua_isnumber(lua,-1) || lua_tonumber(lua,-1) != ++currectArrIndex)
{
lua_pop(lua, 3);
return false;
}
lua_pop(lua, 2);
}
return true;
}


} // namespace lua_backend

#define REF_IMPL_BASIC_FUNC(ValueType) \
Expand Down Expand Up @@ -149,8 +171,11 @@ ValueKind Local<Value>::getKind() const {
} else if (isByteBuffer()) {
return ValueKind::kByteBuffer;
} else if (type == LUA_TTABLE) {
// lua don't have array type, the are all tables
return ValueKind::kObject;
// Traverse the table to judge whether it is an array
if(isArray())
return ValueKind::kArray;
else
return ValueKind::kObject;
} else {
return ValueKind::kUnsupported;
}
Expand All @@ -176,7 +201,11 @@ bool Local<Value>::isFunction() const {
return val_ != 0 && lua_type(lua_backend::currentLua(), val_) == LUA_TFUNCTION;
}

bool Local<Value>::isArray() const { return isObject(); }
bool Local<Value>::isArray() const {
if(val_ == 0 || lua_type(lua_backend::currentLua(), val_) != LUA_TTABLE)
return false;
return lua_backend::judgeIsArray(val_);
}

bool Local<Value>::isByteBuffer() const {
auto engine = lua_backend::currentEngine();
Expand Down Expand Up @@ -437,4 +466,4 @@ void Local<ByteBuffer>::commit() const {}

void Local<ByteBuffer>::sync() const {}

} // namespace script
} // namespace script
105 changes: 99 additions & 6 deletions backend/Python/PyEngine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,87 @@
*/

#include "PyEngine.h"
#include <cstring>
#include "../../src/Utils.h"
#include "../../src/utils/Helper.hpp"

namespace script::py_backend {

PyEngine::PyEngine(std::shared_ptr<utils::MessageQueue> queue)
: queue_(queue ? std::move(queue) : std::make_shared<utils::MessageQueue>()) {
Py_Initialize();
if (Py_IsInitialized() == 0) {
Py_SetStandardStreamEncoding("utf-8", nullptr);
// Python not initialized. Init main interpreter
Py_InitializeEx(0);
// Init threading environment
PyEval_InitThreads();
// Initialize type
namespaceType_ = makeNamespaceType();
staticPropertyType_ = makeStaticPropertyType();
defaultMetaType_ = makeDefaultMetaclass();
// Save main thread state & release GIL
mainThreadState_ = PyEval_SaveThread();
}

// Resume main thread state (to execute Py_NewInterpreter)
PyThreadState* oldState = PyThreadState_Swap(mainThreadState_);

// If GIL is released, lock it
if (PyEngine::engineEnterCount_ == 0) {
PyEval_AcquireLock();
}
// Create new interpreter
PyThreadState* newSubState = Py_NewInterpreter();
if (!newSubState) {
throw Exception("Fail to create sub interpreter");
}
subInterpreterState_ = newSubState->interp;

// If GIL is released before, unlock it
if (PyEngine::engineEnterCount_ == 0) {
PyEval_ReleaseLock();
}
// Store created new sub thread state & recover old thread state stored before
subThreadState_.set(PyThreadState_Swap(oldState));
}

PyEngine::PyEngine() : PyEngine(nullptr) {}

PyEngine::~PyEngine() = default;

void PyEngine::destroy() noexcept { ScriptEngine::destroyUserData(); }
void PyEngine::destroy() noexcept {
ScriptEngine::destroyUserData(); // TODO: solve this problem about Py_EndInterpreter
/*if (PyEngine::engineEnterCount_ == 0) {
// GIL is not locked. Just lock it
PyEval_AcquireLock();
}
// Swap to clear thread state & end sub interpreter
PyThreadState* oldThreadState = PyThreadState_Swap(subThreadState_.get());
Py_EndInterpreter(subThreadState_.get());
// Recover old thread state
PyThreadState_Swap(oldThreadState);

if (PyEngine::engineEnterCount_ == 0) {
// Unlock the GIL because it is not locked before
PyEval_ReleaseLock();
}*/
}

Local<Value> PyEngine::get(const Local<String>& key) { return Local<Value>(); }
Local<Value> PyEngine::get(const Local<String>& key) {
PyObject* item = PyDict_GetItemString(getGlobalDict(), key.toStringHolder().c_str());
if (item)
return py_interop::toLocal<Value>(item);
else
return py_interop::toLocal<Value>(Py_None);
}

void PyEngine::set(const Local<String>& key, const Local<Value>& value) {}
void PyEngine::set(const Local<String>& key, const Local<Value>& value) {
int result =
PyDict_SetItemString(getGlobalDict(), key.toStringHolder().c_str(), py_interop::getPy(value));
if (result != 0) {
checkPyErr();
}
}

Local<Value> PyEngine::eval(const Local<String>& script) { return eval(script, Local<Value>()); }

Expand All @@ -42,7 +105,38 @@ Local<Value> PyEngine::eval(const Local<String>& script, const Local<String>& so
}

Local<Value> PyEngine::eval(const Local<String>& script, const Local<Value>& sourceFile) {
return Local<Value>();
// Limitation: one line code must be expression (no "\n", no "=")
const char* source = script.toStringHolder().c_str();
bool oneLine = true;
if (strstr(source, "\n") != NULL)
oneLine = false;
else if (strstr(source, " = ") != NULL)
oneLine = false;
PyObject* result = PyRun_StringFlags(source, oneLine ? Py_eval_input : Py_file_input,
getGlobalDict(), nullptr, nullptr);
checkPyErr();
return py_interop::asLocal<Value>(result);
}

Local<Value> PyEngine::loadFile(const Local<String>& scriptFile) {
std::string sourceFilePath = scriptFile.toString();
if (sourceFilePath.empty()) {
throw Exception("script file no found");
}
Local<Value> content = internal::readAllFileContent(scriptFile);
if (content.isNull()) {
throw Exception("can't load script file");
}

std::size_t pathSymbol = sourceFilePath.rfind("/");
if (pathSymbol != -1) {
sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
} else {
pathSymbol = sourceFilePath.rfind("\\");
if (pathSymbol != -1) sourceFilePath = sourceFilePath.substr(pathSymbol + 1);
}
Local<String> sourceFileName = String::newString(sourceFilePath);
return eval(content.asString(), sourceFileName);
}

std::shared_ptr<utils::MessageQueue> PyEngine::messageQueue() { return queue_; }
Expand All @@ -56,5 +150,4 @@ ScriptLanguage PyEngine::getLanguageType() { return ScriptLanguage::kPython; }
std::string PyEngine::getEngineVersion() { return Py_GetVersion(); }

bool PyEngine::isDestroying() const { return false; }

} // namespace script::py_backend
Loading