JniLocalRef::JniLocalRef(const JniLocalRef& rhs)
{
	JEnv env;

	m_obj = rhs.m_isWeak ? rhs.m_obj : env.NewLocalRef(rhs.m_obj);
	m_isWeak = rhs.m_isWeak;
}
jobject NativeScriptRuntime::CreateJavaInstance(int objectID, const std::string& fullClassName, const ArgsWrapper& argWrapper, jclass javaClass, bool isInterface)
{
	SET_PROFILER_FRAME();

	jobject instance = nullptr;
	DEBUG_WRITE("CreateJavaInstance:  %s", fullClassName.c_str());

	JEnv env;
	auto& args = argWrapper.args;

	JsArgToArrayConverter argConverter(args, isInterface, argWrapper.outerThis);
	if (argConverter.IsValid())
	{
		jobjectArray javaArgs = argConverter.ToJavaArray();

		int ctorId = GetCachedConstructorId(env, args, fullClassName, javaArgs, javaClass);

		jobject obj = env.CallStaticObjectMethod(PlatformClass,
				CREATE_INSTANCE_METHOD_ID,
				javaArgs,
				(jint) objectID,
				ctorId);


		instance = obj;
	}
	else
	{
		JsArgToArrayConverter::Error err = argConverter.GetError();
		throw NativeScriptException(err.msg);
	}

	return instance;
}
void JsDebugger::DebugBreakCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
{
	if (s_jsDebugger == nullptr)
	{
		return;
	}

	try
	{
		JEnv env;
		env.CallStaticVoidMethod(s_JsDebuggerClass, s_EnableAgent);

		DebugBreak();
	}
	catch (NativeScriptException& e)
	{
		e.ReThrowToV8();
	}
	catch (std::exception e) {
		stringstream ss;
		ss << "Error: c++ exception: " << e.what() << endl;
		NativeScriptException nsEx(ss.str());
		nsEx.ReThrowToV8();
	}
	catch (...) {
		NativeScriptException nsEx(std::string("Error: c++ exception!"));
		nsEx.ReThrowToV8();
	}
}
int NativeScriptRuntime::GetCachedConstructorId(JEnv& env, const FunctionCallbackInfo<Value>& args, const string& fullClassName, jobjectArray javaArgs, jclass javaClass)
{
	int ctorId = -1;
	string encodedCtorArgs = MethodCache::EncodeSignature(fullClassName, "<init>", args, false);
	auto itFound = s_constructorCache.find(encodedCtorArgs);


	if (itFound != s_constructorCache.end())
	{
		ctorId = itFound->second;
	}
	else
	{
		jint id = env.CallStaticIntMethod(PlatformClass, CACHE_CONSTRUCTOR_METHOD_ID, javaClass, javaArgs);

		if (env.ExceptionCheck() == JNI_FALSE)
		{
			ctorId = id;
			s_constructorCache.insert(make_pair(encodedCtorArgs, ctorId));
		}
	}

	DEBUG_WRITE("GetCachedConstructorId: encodedCtorArgs=%s, ctorId=%d", encodedCtorArgs.c_str(), ctorId);
	return ctorId;
}
void ObjectManager::MakeRegularObjectsWeak(const set<int>& instances, DirectBuffer& inputBuff)
{
	JEnv env;

	jboolean keepAsWeak = JNI_FALSE;

	for (auto javaObjectId : instances)
	{
		bool success = inputBuff.Write(javaObjectId);

		if (!success)
		{
			int length = inputBuff.Length();
			env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, length, keepAsWeak);
			inputBuff.Reset();
			success = inputBuff.Write(javaObjectId);
			assert(success);
		}
	}
	int size = inputBuff.Size();
	if (size > 0)
	{
		env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, size, keepAsWeak);
	}

	inputBuff.Reset();
}
jclass NativeScriptRuntime::ResolveClass(const std::string& fullClassname, const Local<Object>& implementationObject) {

	auto itFound = s_classCache.find(fullClassname);

	jclass globalRefToGeneratedClass;

	if (itFound != s_classCache.end())
	{
		globalRefToGeneratedClass = itFound->second;
	}
	else
	{
		JEnv env;

		//get needed arguments in order to load binding
		JniLocalRef javaFullClassName(env.NewStringUTF(fullClassname.c_str()));

		jobjectArray methodOverrides = GetMethodOverrides(env, implementationObject);

		//create or load generated binding (java class)
		JniLocalRef generatedClass(env.CallStaticObjectMethod(PlatformClass, RESOLVE_CLASS_METHOD_ID,  (jstring)javaFullClassName, methodOverrides));
		globalRefToGeneratedClass = reinterpret_cast<jclass>(env.NewGlobalRef(generatedClass));

		s_classCache.insert(make_pair(fullClassname, globalRefToGeneratedClass));
	}

	return globalRefToGeneratedClass;
}
jobject ObjectManager::GetJavaObjectByIDImpl(uint32_t javaObjectID)
{
	JEnv env;

	jobject object = env.CallStaticObjectMethod(PlatformClass, GET_JAVAOBJECT_BY_ID_METHOD_ID, javaObjectID);
	return object;
}
void ObjectManager::MakeImplObjectsWeak(const vector<PersistentObjectIdPair>& instances, DirectBuffer& inputBuff)
{
	JEnv env;

	jboolean keepAsWeak = JNI_TRUE;

	for (const auto& poIdPair : instances)
	{
		int javaObjectId = poIdPair.javaObjectId;

		bool success = inputBuff.Write(javaObjectId);

		if (!success)
		{
			int length = inputBuff.Length();
			jboolean keepAsWeak = JNI_TRUE;
			env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, length, keepAsWeak);
			inputBuff.Reset();
			success = inputBuff.Write(javaObjectId);
			assert(success);
		}
	}
	int size = inputBuff.Size();
	if (size > 0)
	{
		jboolean keepAsWeak = JNI_TRUE;
		env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, size, keepAsWeak);
	}

	inputBuff.Reset();
}
bool NativeScriptRuntime::RegisterInstance(const Local<Object>& jsObject, const std::string& fullClassName, const ArgsWrapper& argWrapper, const Local<Object>& implementationObject, bool isInterface)
{
	bool success;

	DEBUG_WRITE("RegisterInstance called for '%s'", fullClassName.c_str());

	JEnv env;

	jclass generatedJavaClass = ResolveClass(fullClassName, implementationObject);

	int javaObjectID = objectManager->GenerateNewObjectID();

	DEBUG_WRITE("RegisterInstance: Linking new instance");
	objectManager->Link(jsObject, javaObjectID, nullptr);

	jobject instance = CreateJavaInstance(javaObjectID, fullClassName, argWrapper, generatedJavaClass, isInterface);

	JniLocalRef localInstance(instance);
	success = !localInstance.IsNull();

	if (success)
	{
		DEBUG_WRITE("RegisterInstance: Updating linked instance with its real class");
		jclass instanceClass = env.FindClass(fullClassName);
		objectManager->SetJavaClass(jsObject, instanceClass);
	}
	else
	{
		DEBUG_WRITE("RegisterInstance failed with null new instance");
	}

	return success;
}
string ObjectManager::GetClassName(jobject javaObject)
{
	JEnv env;

	JniLocalRef objectClass(env.GetObjectClass(javaObject));

	return GetClassName((jclass) objectClass);
}
Local<Object> ObjectManager::CreateJSWrapper(jint javaObjectID, const string& typeName, jobject instance)
{
	JEnv env;

	JniLocalRef clazz(env.GetObjectClass(instance));

	return CreateJSWrapperHelper(javaObjectID, typeName, clazz);
}
int ObjectManager::GetOrCreateObjectId(jobject object)
{
	JEnv env;

	jint javaObjectID = env.CallStaticIntMethod(PlatformClass, GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID, object);

	return javaObjectID;
}
void NativeScriptRuntime::APP_FAIL(const char *message)
{
	//ASSERT_FAIL(message);

	JEnv env;
	jstring msg = env.NewStringUTF(message);
	env.CallStaticVoidMethod(PlatformClass, APP_FAIL_METHOD_ID, msg);
}
JniLocalRef::~JniLocalRef()
{
	if ((m_obj != nullptr) && !m_isWeak)
	{
		JEnv env;
		env.DeleteLocalRef(m_obj);
	}
}
void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
{
	SET_PROFILER_FRAME();

	ASSERT_MESSAGE(args.Length() == 2, "require should be called with two parameters");
	ASSERT_MESSAGE(!args[0]->IsUndefined() && !args[0]->IsNull(), "require called with undefined moduleName parameter");
	ASSERT_MESSAGE(!args[1]->IsUndefined() && !args[1]->IsNull(), "require called with undefined callingModulePath parameter");
	ASSERT_MESSAGE(args[0]->IsString(), "require should be called with string parameter");
	ASSERT_MESSAGE(args[1]->IsString(), "require should be called with string parameter");

	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(RequireClass, GET_MODULE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsCallingModuleDirName));

	auto isolate = Isolate::GetCurrent();

	// 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);
	if(modulePath == ""){
		// module not found
		stringstream ss;
		ss << "Module \"" << moduleName << "\" not found";
		string exception = ss.str();
		ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception);
		return;
	}
	if (modulePath == "EXTERNAL_FILE_ERROR")
	{
		// module not found
		stringstream ss;
		ss << "Module \"" << moduleName << "\" is located on the external storage. Modules can be private application files ONLY";
		string exception = ss.str();
		ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception);
		return;
	}

	auto it = loadedModules.find(modulePath);

	Handle<Object> moduleObj;
	bool hasError = false;

	if (it == loadedModules.end())
	{
		CompileAndRun(modulePath, hasError, moduleObj, false/*is bootstrap call*/);
	}
	else
	{
		moduleObj = Local<Object>::New(isolate, *((*it).second));
	}

	if(!hasError){
		args.GetReturnValue().Set(moduleObj);
	}
}
int NativeScriptRuntime::GetArrayLength(const Local<Object>& arr)
{
	JEnv env;

	auto javaArr = reinterpret_cast<jarray>(objectManager->GetJavaObjectByJsObject(arr));

	auto length = env.GetArrayLength(javaArr);

	return length;
}
jweak ObjectManager::NewWeakGlobalRefCallback(const int& javaObjectID, void *state)
{
	ObjectManager *objManager = reinterpret_cast<ObjectManager*>(state);

	JniLocalRef obj(objManager->GetJavaObjectByIDImpl(javaObjectID));

	JEnv env;
	jweak weakRef = env.NewWeakGlobalRef(obj);

	return weakRef;
}
string ObjectManager::GetClassName(jclass clazz)
{
	JEnv env;

	JniLocalRef javaCanonicalName(env.CallObjectMethod(clazz, GET_NAME_METHOD_ID));

	string className = ArgConverter::jstringToString(javaCanonicalName);

	std::replace(className.begin(), className.end(), '.', '/');

	return className;
}
Beispiel #19
0
void Module::Init(Isolate *isolate)
{
	JEnv env;

	MODULE_CLASS = env.FindClass("com/tns/Module");
	assert(MODULE_CLASS != nullptr);

	RESOLVE_PATH_METHOD_ID = env.GetStaticMethodID(MODULE_CLASS, "resolvePath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
	assert(RESOLVE_PATH_METHOD_ID != nullptr);

	string requireFactoryScript =
	"(function () { "
	"	function require_factory(requireInternal, dirName) { "
	"		return function require(modulePath) { "
	"			if(global.__requireOverride) { "
	"				var result = global.__requireOverride(modulePath, dirName); "
	"				if(result) { "
	"					return result; "
	"				} "
	"			} "
	"			return requireInternal(modulePath, dirName); "
	"		} "
	"	} "
	"	return require_factory; "
	"})()";

	auto source = ConvertToV8String(requireFactoryScript);
	auto context = isolate->GetCurrentContext();

	Local<Script> script;
	auto maybeScript = Script::Compile(context, source).ToLocal(&script);

	assert(!script.IsEmpty());

	Local<Value> result;
	auto maybeResult = script->Run(context).ToLocal(&result);

	assert(!result.IsEmpty() && result->IsFunction());

	auto requireFactoryFunction = result.As<Function>();

	auto cache = GetCache(isolate);

	cache->RequireFactoryFunction = new Persistent<Function>(isolate, requireFactoryFunction);

	auto requireFuncTemplate = FunctionTemplate::New(isolate, RequireCallback);
	auto requireFunc = requireFuncTemplate->GetFunction();
	cache->RequireFunction = new Persistent<Function>(isolate, requireFunc);

	auto global = isolate->GetCurrentContext()->Global();
	auto globalRequire = GetRequireFunction(isolate, Constants::APP_ROOT_FOLDER_PATH);
	global->Set(ConvertToV8String("require"), globalRequire);
}
void NativeScriptRuntime::DumpReferenceTablesMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
{
	JEnv env;
	jclass vmDbgClass = env.FindClass("dalvik/system/VMDebug");
	if (vmDbgClass != nullptr)
	{
		jmethodID mid = env.GetStaticMethodID(vmDbgClass, "dumpReferenceTables", "()V");
		if (mid != 0)
		{
			env.CallStaticVoidMethod(vmDbgClass, mid);
		}
	}
}
bool NativeScriptRuntime::RegisterInstance(const Handle<Object>& jsObject, const std::string& fullClassName, const ArgsWrapper& argWrapper, const Handle<Object>& implementationObject, bool isInterface)
{
	bool success;

	DEBUG_WRITE("RegisterInstance called for '%s'", fullClassName.c_str());

	if(fullClassName == "java/lang/Object_") {
		int a = 5;
	}
	JEnv env;

	// get class from implementation object if you can
	jclass generatedJavaClass = nullptr;
	bool classIsResolved = false;
	if (!implementationObject.IsEmpty())
	{
		Local < Value > val = implementationObject->GetHiddenValue(ConvertToV8String(fullClassName));
		if (!val.IsEmpty())
		{
			void* voidPointerToVal = val.As<External>()->Value();
			generatedJavaClass = reinterpret_cast<jclass>(voidPointerToVal);
			classIsResolved = true;
		}
	}
	if(!classIsResolved) {
		generatedJavaClass = ResolveClass(fullClassName, implementationObject);
	}

	int javaObjectID = objectManager->GenerateNewObjectID();

	DEBUG_WRITE("RegisterInstance: Linking new instance");
	objectManager->Link(jsObject, javaObjectID, nullptr);

	jobject instance = CreateJavaInstance(javaObjectID, fullClassName, argWrapper, generatedJavaClass, isInterface);

	JniLocalRef localInstance(instance);
	success = !localInstance.IsNull();

	if (success)
	{
		DEBUG_WRITE("RegisterInstance: Updating linked instance with its real class");
		jclass instanceClass = env.FindClass(fullClassName);
		objectManager->SetJavaClass(jsObject, instanceClass);
	}
	else
	{
		DEBUG_WRITE("RegisterInstance failed with null new instance");
	}

	return success;
}
ObjectManager::ObjectManager()
:
		m_numberOfGC(0), m_currentObjectId(0), m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this)
{
	JEnv env;

	PlatformClass = env.FindClass("com/tns/Platform");
	assert(PlatformClass != nullptr);

	GET_JAVAOBJECT_BY_ID_METHOD_ID = env.GetStaticMethodID(PlatformClass, "getJavaObjectByID", "(I)Ljava/lang/Object;");
	assert(GET_JAVAOBJECT_BY_ID_METHOD_ID != nullptr);

	GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID = env.GetStaticMethodID(PlatformClass, "getOrCreateJavaObjectID", "(Ljava/lang/Object;)I");
	assert(GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID != nullptr);

	MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = env.GetStaticMethodID(PlatformClass, "makeInstanceWeak", "(Ljava/nio/ByteBuffer;IZ)V");
	assert(MAKE_INSTANCE_WEAK_BATCH_METHOD_ID != nullptr);

	CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = env.GetStaticMethodID(PlatformClass, "checkWeakObjectAreAlive", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;I)V");
	assert(CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID != nullptr);

	JAVA_LANG_CLASS = env.FindClass("java/lang/Class");
	assert(JAVA_LANG_CLASS != nullptr);

	GET_NAME_METHOD_ID = env.GetMethodID(JAVA_LANG_CLASS, "getName", "()Ljava/lang/String;");
	assert(GET_NAME_METHOD_ID != nullptr);

	ObjectManager::instance = this;
}
/* *
 * private method that takes debug message as json from v8
 * after it gets the message the message handler passes it to enqueueMessage method in java
 */
void JsDebugger::MyMessageHandler(const v8::Debug::Message& message)
{
	if (s_jsDebugger == nullptr)
	{
		return;
	}

	auto json = message.GetJSON();
	auto str = ConvertToString(json);

	JEnv env;
	JniLocalRef s(env.NewStringUTF(str.c_str()));
	env.CallVoidMethod(s_jsDebugger, s_EnqueueMessage, (jstring) s);
}
void ObjectManager::CheckWeakObjectsAreAlive(const vector<PersistentObjectIdPair>& instances, DirectBuffer& inputBuff, DirectBuffer& outputBuff)
{
	JEnv env;

	for (const auto& poIdPair : instances)
	{
		int javaObjectId = poIdPair.javaObjectId;

		bool success = inputBuff.Write(javaObjectId);

		if (!success)
		{
			int length = inputBuff.Length();
			env.CallStaticVoidMethod(PlatformClass, CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID, (jobject) inputBuff, (jobject) outputBuff, length);
			//
			int *released = outputBuff.GetData();
			for (int i = 0; i < length; i++)
			{
				bool isReleased = *released++ != 0;

				if (isReleased)
				{
					Persistent<Object> *po = instances[i].po;
					po->Reset();
				}
			}
			//
			inputBuff.Reset();
			success = inputBuff.Write(javaObjectId);
			assert(success);
		}
	}
	int size = inputBuff.Size();
	if (size > 0)
	{
		env.CallStaticVoidMethod(PlatformClass, CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID, (jobject) inputBuff, (jobject) outputBuff, size);
		int *released = outputBuff.GetData();
		for (int i = 0; i < size; i++)
		{
			bool isReleased = *released++ != 0;

			if (isReleased)
			{
				Persistent<Object> *po = instances[i].po;
				po->Reset();
			}
		}
	}

}
void NativePlatform::AppInitCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
{
	try {
	auto isolate = Isolate::GetCurrent();

	if (args.Length() != 1)
	{
		throw NativeScriptException(string("Application should be initialized with single parameter"));
	}
	if (!args[0]->IsObject())
	{
		throw NativeScriptException(string("Application should be initialized with single object parameter containing overridden methods"));
	}

	// TODO: find another way to get "com/tns/NativeScriptApplication" metadata (move it to more appropriate place)
	auto node = MetadataNode::GetOrCreate("com/tns/NativeScriptApplication");
	auto appInstance = node->CreateJSWrapper(isolate);
	DEBUG_WRITE("Application object created id: %d", appInstance->GetIdentityHash());

	auto implementationObject = args[0]->ToObject();
	implementationObject->SetHiddenValue(V8StringConstants::GetClassImplementationObject(), External::New(isolate, node));
	DEBUG_WRITE("Application object implementation object is with id: %d", implementationObject->GetIdentityHash());
	implementationObject->SetPrototype(appInstance->GetPrototype());
	bool appSuccess = appInstance->SetPrototype(implementationObject);
	if (!appSuccess)
	{
		throw NativeScriptException(string("Application could not be initialized correctly"));
	}

	jweak applicationObject = g_objectManager->GetJavaObjectByID(AppJavaObjectID);

	JEnv env;
	jclass appClass = env.FindClass("com/tns/NativeScriptApplication");
	g_objectManager->Link(appInstance, AppJavaObjectID, appClass);

	JniLocalRef applicationClass(env.GetObjectClass(applicationObject));
	jmethodID setNativeScriptOverridesMethodId = env.GetMethodID((jclass)applicationClass, "setNativeScriptOverrides", "([Ljava/lang/String;)V");
	jobjectArray methodOverrides = NativeScriptRuntime::GetMethodOverrides(env, implementationObject);
	env.CallVoidMethod(applicationObject, setNativeScriptOverridesMethodId, methodOverrides);
	} catch (NativeScriptException& e) {
		e.ReThrowToV8();
	}
	catch (exception e) {
		DEBUG_WRITE("Error: c++ exception: %s", e.what());
	}
	catch (...) {
		DEBUG_WRITE("Error: c++ exception!");
	}
}
jclass NativeScriptRuntime::ResolveClass(const std::string& fullClassname, const Handle<Object>& implementationObject) {

	JEnv env;

	//get needed arguments in order to load binding
	JniLocalRef javaFullClassName(env.NewStringUTF(fullClassname.c_str()));

	jobjectArray methodOverrides = GetMethodOverrides(env, implementationObject);

	//create or load generated binding (java class)
	JniLocalRef generatedClass(env.CallStaticObjectMethod(PlatformClass, RESOLVE_CLASS_METHOD_ID,  (jstring)javaFullClassName, methodOverrides));
	jclass globalRefToGeneratedClass = reinterpret_cast<jclass>(env.NewGlobalRef(generatedClass));

	return globalRefToGeneratedClass;
}
Local<Value> ArgConverter::jstringToV8String(jstring value)
{
	if	(value == nullptr)
	{
		return Null(Isolate::GetCurrent());
	}

	JEnv env;
	auto chars = env.GetStringChars(value, NULL);
	auto length = env.GetStringLength(value);
	auto v8String = ConvertToV8String(chars, length);
	env.ReleaseStringChars(value, chars);

	return v8String;
}
Local<Object> ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const string& typeName, jclass clazz)
{
	auto isolate = Isolate::GetCurrent();

	auto className = (clazz != nullptr) ? GetClassName(clazz) : typeName;

	auto node = MetadataNode::GetOrCreate(className);

	auto jsWrapper = node->CreateJSWrapper(isolate);

	JEnv env;
	auto claz = env.FindClass(className);
	Link(jsWrapper, javaObjectID, claz);
	return jsWrapper;
}
void NativeScriptRuntime::DisableVerboseLoggingMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
{
	try {
	tns::LogEnabled = false;
	JEnv env;
	env.CallStaticVoidMethod(PlatformClass, DISABLE_VERBOSE_LOGGING_METHOD_ID);
	} catch (NativeScriptException& e) {
		e.ReThrowToV8();
	}
	catch (exception e) {
		DEBUG_WRITE("Error: c++ exception: %s", e.what());
	}
	catch (...) {
		DEBUG_WRITE("Error: c++ exception!");
	}
}
JsArgToArrayConverter::~JsArgToArrayConverter()
{
	if (m_argsLen > 0)
	{
		JEnv env;

		int length = m_storedIndexes.size();
		for (int i = 0; i < length; i++)
		{
			int index = m_storedIndexes[i];
			env.DeleteLocalRef(m_argsAsObject[index]);
		}

		delete[] m_argsAsObject;
	}
}