Skip to content

Commit

Permalink
[unity] fix #1540
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieyang authored Sep 29, 2023
1 parent ff2deff commit 2be8266
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 25 deletions.
4 changes: 3 additions & 1 deletion unity/native_src/Inc/BackendEnv.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,16 @@ namespace puerts
v8::MaybeLocal<v8::Module> _ResolveModule(
v8::Local<v8::Context> Context,
v8::Local<v8::String> Specifier,
v8::Local<v8::Module> Referrer,
v8::Local<v8::Value> Referrer,
bool& isFromCache
);

v8::MaybeLocal<v8::Module> ResolveModule( v8::Local<v8::Context> Context, v8::Local<v8::String> Specifier, v8::Local<v8::Module> Referrer);

bool LinkModule(v8::Local<v8::Context> Context, v8::Local<v8::Module> RefModule);

v8::MaybeLocal<v8::Promise> DynamicImport(v8::Local<v8::Context> Context, v8::Local<v8::ScriptOrModule> Referrer, v8::Local<v8::String> Specifier);

void HostInitializeImportMetaObject(v8::Local<v8::Context> Context, v8::Local<v8::Module> Module, v8::Local<v8::Object> meta);
#else
JSModuleDef* js_module_loader(JSContext* ctx, const char *name, void *opaque);
Expand Down
105 changes: 81 additions & 24 deletions unity/native_src/Src/BackendEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ void puerts::BackendEnv::InitInject(v8::Isolate* Isolate, v8::Local<v8::Context>

NodeIsolateData = node::CreateIsolateData(Isolate, &NodeUVLoop, Platform, NodeArrayBufferAllocator.get()); // node::FreeIsolateData

NodeEnv = CreateEnvironment(NodeIsolateData, Context, *Args, *ExecArgs, node::EnvironmentFlags::kOwnsProcessState);
NodeEnv = CreateEnvironment(NodeIsolateData, Context, *Args, *ExecArgs, (node::EnvironmentFlags::Flags)(node::EnvironmentFlags::kOwnsProcessState | node::EnvironmentFlags::kNoRegisterESMLoader | node::EnvironmentFlags::kNoCreateInspector));

Global->Set(Context, strConsole, Console).Check();

Expand All @@ -341,6 +341,7 @@ void puerts::BackendEnv::InitInject(v8::Isolate* Isolate, v8::Local<v8::Context>

#if !WITH_QUICKJS
Isolate->SetHostInitializeImportMetaObjectCallback(&puerts::esmodule::HostInitializeImportMetaObject);
Isolate->SetHostImportModuleDynamicallyCallback(&puerts::esmodule::DynamicImport);
#endif

Context->Global()->Set(Context, v8::String::NewFromUtf8(Isolate, "__tgjsSetPromiseRejectCallback").ToLocalChecked(), v8::FunctionTemplate::New(Isolate, &SetPromiseRejectCallback<puerts::BackendEnv>)->GetFunction(Context).ToLocalChecked()).Check();
Expand Down Expand Up @@ -479,6 +480,51 @@ static v8::MaybeLocal<v8::Value> CallRead(

return maybeRet;
}
#if !WITH_QUICKJS
v8::MaybeLocal<v8::Promise> puerts::esmodule::DynamicImport(
v8::Local<v8::Context> Context,
v8::Local<v8::ScriptOrModule> Referrer,
v8::Local<v8::String> Specifier
)
{
bool isFromCache;
v8::Local<v8::Value> ReferrerName = Referrer->GetResourceName();

v8::TryCatch TryCatch(Context->GetIsolate());
v8::MaybeLocal<v8::Module> mod = puerts::esmodule::_ResolveModule(Context, Specifier, ReferrerName, isFromCache);

v8::Local<v8::Promise::Resolver> resolver;
if (!v8::Promise::Resolver::New(Context).ToLocal(&resolver)) return v8::MaybeLocal<v8::Promise> {};

if (mod.IsEmpty())
{
resolver->Reject(Context, TryCatch.Exception());
return resolver->GetPromise();
}
v8::Local<v8::Module> moduleChecked = mod.ToLocalChecked();
if (!puerts::esmodule::LinkModule(Context, moduleChecked))
{
resolver->Reject(Context, TryCatch.Exception());
return resolver->GetPromise();
}
v8::Maybe<bool> ret = moduleChecked->InstantiateModule(Context, puerts::esmodule::ResolveModule);
if (ret.IsNothing() || !ret.ToChecked())
{
resolver->Reject(Context, TryCatch.Exception());
return resolver->GetPromise();
}
v8::MaybeLocal<v8::Value> evalRet = moduleChecked->Evaluate(Context);
if (evalRet.IsEmpty())
{
resolver->Reject(Context, TryCatch.Exception());
return resolver->GetPromise();
}

resolver->Resolve(Context, moduleChecked->GetModuleNamespace());

return resolver->GetPromise();
}
#endif

void puerts::esmodule::ExecuteModule(const v8::FunctionCallbackInfo<v8::Value>& info)
{
Expand Down Expand Up @@ -587,28 +633,12 @@ void puerts::esmodule::ExecuteModule(const v8::FunctionCallbackInfo<v8::Value>&
v8::MaybeLocal<v8::Module> puerts::esmodule::_ResolveModule(
v8::Local<v8::Context> Context,
v8::Local<v8::String> Specifier,
v8::Local<v8::Module> Referrer,
v8::Local<v8::Value> ReferrerName,
bool& isFromCache
)
{
v8::Isolate* Isolate = Context->GetIsolate();
BackendEnv* mm = (BackendEnv*)Isolate->GetData(1);

v8::Local<v8::Value> ReferrerName;
#if V8_94_OR_NEWER
const auto referIter = mm->ScriptIdToPathMap.find(Referrer->ScriptId());
#else
const auto referIter = mm->ScriptIdToPathMap.find(Referrer->GetIdentityHash());
#endif
if (referIter != mm->ScriptIdToPathMap.end())
{
std::string referPath_std = referIter->second;
ReferrerName = v8::String::NewFromUtf8(Isolate, referPath_std.c_str()).ToLocalChecked();
}
else
{
ReferrerName = v8::String::NewFromUtf8(Isolate, "").ToLocalChecked();
}
BackendEnv* mm = BackendEnv::Get(Isolate);

v8::MaybeLocal<v8::Value> maybeRet = CallResolver(Isolate, Context, Specifier, ReferrerName);
if (maybeRet.IsEmpty())
Expand Down Expand Up @@ -668,14 +698,41 @@ v8::MaybeLocal<v8::Module> puerts::esmodule::_ResolveModule(
return Module;
}

v8::Local<v8::Value> GetModuleName(
v8::Isolate* Isolate,
v8::Local<v8::Module> Referrer
)
{
puerts::BackendEnv* mm = puerts::BackendEnv::Get(Isolate);
v8::Local<v8::Value> ReferrerName;
#if V8_94_OR_NEWER
const auto referIter = mm->ScriptIdToPathMap.find(Referrer->ScriptId());
#else
const auto referIter = mm->ScriptIdToPathMap.find(Referrer->GetIdentityHash());
#endif
if (referIter != mm->ScriptIdToPathMap.end())
{
std::string referPath_std = referIter->second;
ReferrerName = v8::String::NewFromUtf8(Isolate, referPath_std.c_str()).ToLocalChecked();
}
else
{
ReferrerName = v8::String::NewFromUtf8(Isolate, "").ToLocalChecked();
}
return ReferrerName;
}

v8::MaybeLocal<v8::Module> puerts::esmodule::ResolveModule(
v8::Local<v8::Context> Context,
v8::Local<v8::String> Specifier,
v8::Local<v8::Module> Referrer
)
{
v8::Isolate* Isolate = Context->GetIsolate();
bool isFromCache = false;
return _ResolveModule(Context, Specifier, Referrer, isFromCache);
v8::Local<v8::Value> ReferrerName = GetModuleName(Isolate, Referrer);

return _ResolveModule(Context, Specifier, ReferrerName, isFromCache);
}

bool puerts::esmodule::LinkModule(
Expand All @@ -690,7 +747,7 @@ bool puerts::esmodule::LinkModule(
v8::Local<v8::String> Specifier_v8 = RefModule->GetModuleRequest(i);

bool isFromCache = false;
v8::MaybeLocal<v8::Module> MaybeModule = _ResolveModule(Context, Specifier_v8, RefModule, isFromCache);
v8::MaybeLocal<v8::Module> MaybeModule = _ResolveModule(Context, Specifier_v8, GetModuleName(Isolate, RefModule), isFromCache);
if (MaybeModule.IsEmpty())
{
return false;
Expand All @@ -710,7 +767,7 @@ bool puerts::esmodule::LinkModule(
void puerts::esmodule::HostInitializeImportMetaObject(v8::Local<v8::Context> Context, v8::Local<v8::Module> Module, v8::Local<v8::Object> meta)
{
v8::Isolate* Isolate = Context->GetIsolate();
BackendEnv* mm = (BackendEnv*)Isolate->GetData(1);
BackendEnv* mm = BackendEnv::Get(Isolate);

#if V8_94_OR_NEWER
auto iter = mm->ScriptIdToPathMap.find(Module->ScriptId());
Expand All @@ -734,7 +791,7 @@ char* puerts::esmodule::js_module_resolver(
{
JSRuntime *rt = JS_GetRuntime(ctx);
v8::Isolate* Isolate = (v8::Isolate*)JS_GetRuntimeOpaque(rt);
BackendEnv* mm = (BackendEnv*)Isolate->GetData(1);
BackendEnv* mm = BackendEnv::Get(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();

v8::Local<v8::Value> Specifier = v8::String::NewFromUtf8(Isolate, name).ToLocalChecked();
Expand Down Expand Up @@ -771,7 +828,7 @@ JSModuleDef* puerts::esmodule::js_module_loader(
{
JSRuntime *rt = JS_GetRuntime(ctx);
v8::Isolate* Isolate = (v8::Isolate*)JS_GetRuntimeOpaque(rt);
BackendEnv* mm = (BackendEnv*)Isolate->GetData(1);
BackendEnv* mm = BackendEnv::Get(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();

std::string name_std(name, strlen(name));
Expand Down
58 changes: 58 additions & 0 deletions unity/test/Src/Cases/API/EvalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,5 +311,63 @@ public void ESModuleExecuteCJSRelative()
jsEnv.Tick();

}


[Test]
public void ESDynamicModuleNotFound()
{
var jsEnv = UnitTestEnv.GetEnv();
jsEnv.Eval(@"
import('notfound/whatever.mjs')
.catch(e => {
global.error_ESDynamicModuleNotFound = e
})
");
jsEnv.Tick();
StringAssert.Contains("notfound/whatever.mjs", jsEnv.Eval<string>("error_ESDynamicModuleNotFound.toString()"));
}
#if !UNITY_WEBGL || UNITY_EDITOR
[Test]
public void ESDynamicModuleCompileError()
{
var loader = UnitTestEnv.GetLoader();
loader.AddMockFileContent("compile-error/whatever2.mjs", @"export delete;");
var jsEnv = UnitTestEnv.GetEnv();
jsEnv.Eval(@"
import('compile-error/whatever2.mjs')
.catch(e => {
global.error_ESDynamicModuleCompileError = e
})
");
jsEnv.Tick();
StringAssert.Contains("export", jsEnv.Eval<string>("error_ESDynamicModuleCompileError.toString()"));
}
#endif
[Test]
public void ESDynamicModuleEvaluateError()
{
var jsEnv = UnitTestEnv.GetEnv();
jsEnv.Eval(@"
import('eval-error/whatever.mjs')
.catch(e => {
global.error_ESDynamicModuleEvaluateError = e
})
");
jsEnv.Tick();
StringAssert.Contains("not a function", jsEnv.Eval<string>("error_ESDynamicModuleEvaluateError.toString()"));
}
[Test]
public void ESDynamicModuleImportRelative()
{
var jsEnv = UnitTestEnv.GetEnv();
jsEnv.Eval(@"
import('import-relative/a/entry.mjs')
.then(r => {
global.result_ESDynamicModuleImportRelative = r.str
})
");
jsEnv.Tick();
StringAssert.Contains("hello", jsEnv.Eval<string>("result_ESDynamicModuleImportRelative.toString()"));
}
}
}

0 comments on commit 2be8266

Please sign in to comment.