-
Notifications
You must be signed in to change notification settings - Fork 811
Description
前置阅读 | Pre-reading
Puer的版本 | Puer Version
Master(>1.0.9)
UE的版本 | UE Version
5.6.1
发生在哪个平台 | Platform
Editor(win)
错误信息 | Error Message
准备使用QuickJS作为backend以便支持v8无法支持的平台,包括NS和PS的平台。但是切换到QuickJS的时候发现了一些问题。
我们的注册代码发生在另外一个模块(DLL)里面。当我们使用C++绑定去注册一些API给TS的时候,带参数的函数调用,在参数传递时都会产生崩溃。例如在C++中是如此注册的API:
struct FBindTest
{
static void CallFuncWithBoolean(bool Value)
{
UE_LOG(LogTemp, Log, TEXT("CallFuncWithBoolean: %d"), Value);
}
static void CallFuncWithString(const FString& Value)
{
UE_LOG(LogTemp, Log, TEXT("CallFuncWithBoolean: %s"), *Value);
}
static void CallFuncWithInt(int Value)
{
UE_LOG(LogTemp, Log, TEXT("CallFuncWithInt: %d"), Value);
}
};
UsingCppType(FBindTest);
void BindJSExtension()
{
puerts::DefineClass<FBindTest>()
.Function("CallFuncWithBoolean", MakeFunction(&FBindTest::CallFuncWithBoolean))
.Function("CallFuncWithString", MakeFunction(&FBindTest::CallFuncWithString))
.Function("CallFuncWithInt", MakeFunction(&FBindTest::CallFuncWithInt))
.Register();
}
在脚本中用引擎类继承派生了一个GameModeBase,其中调用这个C++的API。如下使用:
class StartupGameMode extends UE.GameModeBase {
override ReceiveBeginPlay(): void {
console.info("## Statup Game");
cpp.FBindTest.CallFuncWithBoolean(true);
cpp.FBindTest.CallFuncWithString('Hello');
cpp.FBindTest.CallFuncWithInt(1);
console.info("## Statup Game End");
}
}
实际QuickJs作为backend的时候,传递int参数会产生崩溃:
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Int32Value(context).ToChecked());
}
Maybe<int32_t> Value::Int32Value(Local<Context> context) const {
double d;
if (JS_ToFloat64(Isolate::current_->current_context_->context_, &d, value_)) {
return Maybe<int32_t>();
}
else {
return Maybe<int32_t>((int32_t)d);
}
}
发现一种情况是如果在JsEnv.Build.cs中把ForceStaticLibInEditor = true给去掉,这个问题会解决。可能是因为一个静态库如果有两个DLL模块访问的话,其中的静态变量会每个模块有一份。对于QuickJS的实现来说,static Isolate* current_;这个静态变量会碰到这个问题。只要访问Puerts的C++注册代码发生在多个模块,就可能出现这个问题。最好的方法是避免这个静态变量,似乎大部分访问都可以通过传递的参数获取到Isolate。
问题重现 | Bug reproduce
我构造了一个演示工程:https://github.com/watsonsong/Puerts_QuickJSTest
下载这个工程,使用UE 5.6.1或者其他版本打开。打开默认是Startup的一个空场景,PIE直接运行Startup可以复现。
BTW顺便Quick下还有一个问题是
JsEnv->Start("PuertsEditor/CodeAnalyze");执行速度非常慢,会在编辑器启动时卡很久。主要时间消耗在:let diagnostics = ts.getPreEmitDiagnostics(program);上面。即使这个测试工程都会非常慢,如果比较大一些的工程就几乎不可用。