Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 53 additions & 26 deletions src/jni/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,9 @@ void Module::RequireCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args

string moduleName = ConvertToString(args[0].As<String>());
string callingModuleDirName = ConvertToString(args[1].As<String>());

JEnv env;
JniLocalRef jsModulename(env.NewStringUTF(moduleName.c_str()));
JniLocalRef jsCallingModuleDirName(env.NewStringUTF(callingModuleDirName.c_str()));
JniLocalRef jsModulePath(env.CallStaticObjectMethod(MODULE_CLASS, RESOLVE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsCallingModuleDirName));

// cache the required modules by full path, not name only, since there might be some collisions with relative paths and names
string modulePath = ArgConverter::jstringToString((jstring) jsModulePath);

auto isData = false;

auto moduleObj = LoadImpl(isolate, modulePath, isData);
auto moduleObj = LoadImpl(isolate, moduleName, callingModuleDirName, isData);

if (isData)
{
Expand Down Expand Up @@ -217,40 +208,64 @@ void Module::Load(const string& path)
}
}

Local<Object> Module::LoadImpl(Isolate *isolate, const string& path, bool& isData)
Local<Object> Module::LoadImpl(Isolate *isolate, const string& moduleName, const string& baseDir, bool& isData)
{
auto pathKind = GetModulePathKind(moduleName);
auto cachePathKey = (pathKind == ModulePathKind::Global) ? moduleName : (baseDir + "*" + moduleName);

Local<Object> result;

auto it = m_loadedModules.find(path);
DEBUG_WRITE(">>LoadImpl cachePathKey=%s", cachePathKey.c_str());

auto it = m_loadedModules.find(cachePathKey);

if (it == m_loadedModules.end())
{
if (Util::EndsWith(path, ".js") || Util::EndsWith(path, ".so"))
{
isData = false;
result = LoadModule(isolate, path);
}
else if (Util::EndsWith(path, ".json"))
JEnv env;
JniLocalRef jsModulename(env.NewStringUTF(moduleName.c_str()));
JniLocalRef jsBaseDir(env.NewStringUTF(baseDir.c_str()));
JniLocalRef jsModulePath(env.CallStaticObjectMethod(MODULE_CLASS, RESOLVE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsBaseDir));

auto path = ArgConverter::jstringToString((jstring) jsModulePath);

auto it2 = m_loadedModules.find(path);

if (it2 == m_loadedModules.end())
{
isData = true;
result = LoadData(isolate, path);
if (Util::EndsWith(path, ".js") || Util::EndsWith(path, ".so"))
{
isData = false;
result = LoadModule(isolate, path, cachePathKey);
}
else if (Util::EndsWith(path, ".json"))
{
isData = true;
result = LoadData(isolate, path);
}
else
{
string errMsg = "Unsupported file extension: " + path;
throw NativeScriptException(errMsg);
}
}
else
{
string errMsg = "Unsupported file extension: " + path;
throw NativeScriptException(errMsg);
auto& cacheEntry = it2->second;
isData = cacheEntry.isData;
result = Local<Object>::New(isolate, *cacheEntry.obj);
}
}
else
{
isData = Util::EndsWith(path, ".json");
result = Local<Object>::New(isolate, *it->second);
auto& cacheEntry = it->second;
isData = cacheEntry.isData;
result = Local<Object>::New(isolate, *cacheEntry.obj);
}

return result;
}

Local<Object> Module::LoadModule(Isolate *isolate, const string& modulePath)
Local<Object> Module::LoadModule(Isolate *isolate, const string& modulePath, const string& moduleCacheKey)
{
Local<Object> result;

Expand All @@ -262,7 +277,7 @@ Local<Object> Module::LoadModule(Isolate *isolate, const string& modulePath)
moduleObj->Set(ConvertToV8String("filename"), fullRequiredModulePath);

auto poModuleObj = new Persistent<Object>(isolate, moduleObj);
TempModule tempModule(this, modulePath, poModuleObj);
TempModule tempModule(this, modulePath, moduleCacheKey, poModuleObj);

TryCatch tc;

Expand Down Expand Up @@ -469,6 +484,18 @@ void Module::SaveScriptCache(const ScriptCompiler::Source& source, const std::st
File::WriteBinary(cachePath, source.GetCachedData()->data, length);
}

Module::ModulePathKind Module::GetModulePathKind(const std::string& path)
{
ModulePathKind kind;
switch (path[0])
{
case '.': kind = ModulePathKind::Relative; break;
case '/': kind = ModulePathKind::Absolute; break;
default: kind = ModulePathKind::Global; break;
}
return kind;
}

jclass Module::MODULE_CLASS = nullptr;
jmethodID Module::RESOLVE_PATH_METHOD_ID = nullptr;

Expand Down
44 changes: 38 additions & 6 deletions src/jni/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ namespace tns
void Load(const std::string& path);

private:
enum class ModulePathKind;

struct ModuleCacheEntry;

static void RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& args);

static void RequireNativeCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand All @@ -34,9 +38,9 @@ namespace tns

v8::Local<v8::String> WrapModuleContent(const std::string& path);

v8::Local<v8::Object> LoadImpl(v8::Isolate *isolate, const std::string& path, bool& isData);
v8::Local<v8::Object> LoadImpl(v8::Isolate *isolate, const std::string& moduleName, const std::string& baseDir, bool& isData);

v8::Local<v8::Object> LoadModule(v8::Isolate *isolate, const std::string& path);
v8::Local<v8::Object> LoadModule(v8::Isolate *isolate, const std::string& path, const std::string& moduleCacheKey);

v8::Local<v8::Object> LoadData(v8::Isolate *isolate, const std::string& path);

Expand All @@ -48,6 +52,8 @@ namespace tns

void SaveScriptCache(const v8::ScriptCompiler::Source& source, const std::string& path);

ModulePathKind GetModulePathKind(const std::string& path);

static jclass MODULE_CLASS;
static jmethodID RESOLVE_PATH_METHOD_ID;
static const char* MODULE_PROLOGUE;
Expand All @@ -57,22 +63,24 @@ namespace tns
v8::Persistent<v8::Function> *m_requireFunction;
v8::Persistent<v8::Function> *m_requireFactoryFunction;
std::map<std::string, v8::Persistent<v8::Function>*> m_requireCache;
std::map<std::string, v8::Persistent<v8::Object>*> m_loadedModules;
std::map<std::string, ModuleCacheEntry> m_loadedModules;

class TempModule
{
public:
TempModule(Module* module, const std::string& modulePath, v8::Persistent<v8::Object> *poModuleObj)
:m_module(module), m_dispose(true), m_modulePath(modulePath), m_poModuleObj(poModuleObj)
TempModule(Module* module, const std::string& modulePath, const std::string& cacheKey, v8::Persistent<v8::Object> *poModuleObj)
:m_module(module), m_dispose(true), m_modulePath(modulePath), m_cacheKey(cacheKey), m_poModuleObj(poModuleObj)
{
m_module->m_loadedModules.insert(make_pair(m_modulePath, m_poModuleObj));
m_module->m_loadedModules.insert(make_pair(m_modulePath, ModuleCacheEntry(m_poModuleObj)));
m_module->m_loadedModules.insert(make_pair(m_cacheKey, ModuleCacheEntry(m_poModuleObj)));
}

~TempModule()
{
if (m_dispose)
{
m_module->m_loadedModules.erase(m_modulePath);
m_module->m_loadedModules.erase(m_cacheKey);
}
}

Expand All @@ -85,8 +93,32 @@ namespace tns
bool m_dispose;
Module *m_module;
std::string m_modulePath;
std::string m_cacheKey;
v8::Persistent<v8::Object> *m_poModuleObj;
};

struct ModuleCacheEntry
{
ModuleCacheEntry(v8::Persistent<v8::Object> *_obj)
: obj(_obj), isData(false)
{
}

ModuleCacheEntry(v8::Persistent<v8::Object> *_obj, bool _isData)
: obj(_obj), isData(_isData)
{
}

bool isData;
v8::Persistent<v8::Object> *obj;
};

enum class ModulePathKind
{
Global,
Relative,
Absolute
};
};
}

Expand Down