Skip to content
Closed
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
4 changes: 2 additions & 2 deletions src/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ LOCAL_CPPFLAGS += -std=c++11
LOCAL_MODULE := NativeScript
LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp AssetExtractor.cpp\
com_tns_Platform.cpp NativePlatform.cpp \
com_tns_JsDebugger.cpp \
com_tns_JsDebugger.cpp com_tns_DirectBufferFactory.cpp \
JEnv.cpp DirectBuffer.cpp NativeScriptException.cpp \
JsDebugger.cpp SimpleAllocator.cpp \
JsDebugger.cpp SimpleAllocator.cpp ArrayBufferHelper.cpp \
NativeScriptRuntime.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \
MethodCache.cpp JavaObjectArrayCache.cpp \
JniSignatureParser.cpp \
Expand Down
116 changes: 116 additions & 0 deletions src/jni/ArrayBufferHelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "ArrayBufferHelper.h"
#include "JEnv.h"
#include "V8GlobalHelpers.h"
#include "NativeScriptException.h"
#include <sstream>


using namespace v8;
using namespace tns;

ArrayBufferHelper::ArrayBufferHelper()
{
}


void ArrayBufferHelper::CreateConvertFunctions(ObjectManager *objectManager, const Local<Object>& global)
{
s_objectManager = objectManager;
auto isolate = Isolate::GetCurrent();
auto fromFunc = FunctionTemplate::New(isolate, CreateFromCallback)->GetFunction();
auto ctx = isolate->GetCurrentContext();
auto arrBufferCtorFunc = global->Get(ConvertToV8String("ArrayBuffer")).As<Function>();
arrBufferCtorFunc->Set(ctx, ConvertToV8String("from"), fromFunc);
}

void ArrayBufferHelper::CreateFromCallback(const FunctionCallbackInfo<Value>& info)
{
try
{
CreateFromCallbackImpl(info);
}
catch (NativeScriptException& e)
{
e.ReThrowToV8();
}
catch (std::exception e) {
std::stringstream ss;
ss << "Error: c++ exception: " << e.what() << std::endl;
NativeScriptException nsEx(ss.str());
nsEx.ReThrowToV8();
}
catch (...) {
NativeScriptException nsEx(std::string("Error: c++ exception!"));
nsEx.ReThrowToV8();
}
}

void ArrayBufferHelper::CreateFromCallbackImpl(const FunctionCallbackInfo<Value>& info)
{
auto isolate = info.GetIsolate();
auto len = info.Length();

if (len != 1)
{
throw NativeScriptException("Wrong number of arguments (1 expected)");
}

auto arg = info[0];

if (!arg->IsObject())
{
throw NativeScriptException("Wrong type of argument (object expected)");
}

auto argObj = arg.As<Object>();

auto obj = s_objectManager->GetJavaObjectByJsObject(argObj);

if (obj.IsNull())
{
throw NativeScriptException("Wrong type of argument (object expected)");
}

JEnv env;

if (s_ByteBufferClass == nullptr)
{
s_ByteBufferClass = env.FindClass("java/nio/ByteBuffer");
assert(s_ByteBufferClass != nullptr);
}

auto isByteBuffer = env.IsInstanceOf(obj, s_ByteBufferClass);

if (!isByteBuffer)
{
throw NativeScriptException("Wrong type of argument (ByteBuffer expected)");
}

if (s_isDirectMethodID == nullptr)
{
s_isDirectMethodID = env.GetMethodID(s_ByteBufferClass, "isDirect", "()Z");
assert(s_isDirectMethodID != nullptr);
}

auto jbool = env.CallBooleanMethod(obj, s_isDirectMethodID);

auto isDirectBuffer = jbool == JNI_TRUE;

if (!isDirectBuffer)
{
throw NativeScriptException("Direct ByteBuffer expected)");
}

auto data = env.GetDirectBufferAddress(obj);
auto size = env.GetDirectBufferCapacity(obj);

auto arrayBuffer = ArrayBuffer::New(isolate, data, size);
auto ctx = isolate->GetCurrentContext();
arrayBuffer->Set(ctx, ConvertToV8String("nativeObject"), argObj);

info.GetReturnValue().Set(arrayBuffer);
}

ObjectManager* ArrayBufferHelper::s_objectManager = nullptr;
jclass ArrayBufferHelper::s_ByteBufferClass = nullptr;
jmethodID ArrayBufferHelper::s_isDirectMethodID = nullptr;
30 changes: 30 additions & 0 deletions src/jni/ArrayBufferHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef ARRAYBUFFERHELPER_H_
#define ARRAYBUFFERHELPER_H_

#include "v8.h"
#include "ObjectManager.h"

namespace tns
{
class ArrayBufferHelper
{
public:
static void CreateConvertFunctions(ObjectManager *objectManager, const v8::Local<v8::Object>& global);

private:
ArrayBufferHelper();

static void CreateFromCallback(const v8::FunctionCallbackInfo<v8::Value>& info);

static void CreateFromCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info);

static ObjectManager *s_objectManager;

static jclass s_ByteBufferClass;

static jmethodID s_isDirectMethodID;
};
}


#endif /* ARRAYBUFFERHELPER_H_ */
24 changes: 24 additions & 0 deletions src/jni/NativePlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "NativeScriptException.h"
#include "NativePlatform.h"
#include "ArrayHelper.h"
#include "ArrayBufferHelper.h"
#include <sstream>
#include <android/log.h>
#include <string>
Expand Down Expand Up @@ -382,6 +383,8 @@ Isolate* NativePlatform::PrepareV8Runtime(JEnv& env, const string& filesPath, js

ArrayHelper::Init(g_objectManager, context);

ArrayBufferHelper::CreateConvertFunctions(g_objectManager, global);

return isolate;
}

Expand Down Expand Up @@ -439,4 +442,25 @@ void NativePlatform::PrepareExtendFunction(Isolate *isolate, jstring filesPath)
DEBUG_WRITE("Executed prepareExtend.js script");
}

jobject NativePlatform::AllocateByteBuffer(JNIEnv *_env, jint capacity, jlongArray address)
{
JEnv env(_env);
jobject buffer = nullptr;
void *data = malloc(capacity);
if (data != nullptr)
{
buffer = env.NewDirectByteBuffer(data, capacity);
}
jlong addr = reinterpret_cast<jlong>(data);
env.SetLongArrayRegion(address, 0, 1, &addr);
return buffer;
}

void NativePlatform::FreeByteBuffer(JNIEnv *_env, jlong address)
{
void *data = reinterpret_cast<void*>(address);
free(data);
}

Isolate* NativePlatform::s_isolate = nullptr;

2 changes: 2 additions & 0 deletions src/jni/NativePlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace tns
static jint GenerateNewObjectId(JNIEnv *env, jobject obj);
static void AdjustAmountOfExternalAllocatedMemoryNative(JNIEnv *env, jobject obj, jlong usedMemory);
static void PassUncaughtExceptionToJsNative(JNIEnv *env, jobject obj, jthrowable exception, jstring stackTrace);
static jobject AllocateByteBuffer(JNIEnv *_env, jint capacity, jlongArray address);
static void FreeByteBuffer(JNIEnv *_env, jlong address);

bool LogEnabled = true;
private:
Expand Down
53 changes: 53 additions & 0 deletions src/jni/com_tns_DirectBufferFactory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "jni.h"
#include "NativePlatform.h"
#include "NativeScriptException.h"
#include <sstream>

using namespace std;
using namespace tns;

extern "C" jobject Java_com_tns_DirectBufferFactory_allocateByteBuffer(JNIEnv *env, jobject obj, jint capacity, jlongArray address)
{
jobject buffer = nullptr;
try
{
buffer = NativePlatform::AllocateByteBuffer(env, capacity, address);
}
catch (NativeScriptException& e)
{
e.ReThrowToJava();
}
catch (std::exception e) {
stringstream ss;
ss << "Error: c++ exception: " << e.what() << endl;
NativeScriptException nsEx(ss.str());
nsEx.ReThrowToJava();
}
catch (...) {
NativeScriptException nsEx(std::string("Error: c++ exception!"));
nsEx.ReThrowToJava();
}
return buffer;
}

extern "C" void Java_com_tns_DirectBufferFactory_freeByteBuffer(JNIEnv *env, jobject obj, jlong address)
{
try
{
NativePlatform::FreeByteBuffer(env, address);
}
catch (NativeScriptException& e)
{
e.ReThrowToJava();
}
catch (std::exception e) {
stringstream ss;
ss << "Error: c++ exception: " << e.what() << endl;
NativeScriptException nsEx(ss.str());
nsEx.ReThrowToJava();
}
catch (...) {
NativeScriptException nsEx(std::string("Error: c++ exception!"));
nsEx.ReThrowToJava();
}
}
87 changes: 87 additions & 0 deletions src/src/com/tns/DirectBufferFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.tns;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;

public class DirectBufferFactory
{
private class DirectBufferWeakReference<T> extends PhantomReference<T>
{
public long address;

public DirectBufferWeakReference(T ref, ReferenceQueue<T> queue, long address)
{
super(ref, queue);
this.address = address;
}
}

private class ReferenceQueueListener implements Runnable
{
public ReferenceQueueListener()
{
}

@Override
public void run()
{
while (true)
{
try
{
@SuppressWarnings("unchecked")
DirectBufferWeakReference<ByteBuffer> ref = (DirectBufferWeakReference<ByteBuffer>) DirectBufferFactory.this.queue.remove();
DirectBufferFactory.this.enqueueBuffers.remove(ref);
freeByteBuffer(ref.address);
}
catch (Throwable t)
{
DirectBufferFactory.this.logger.write(t.getMessage());
}
}
}
}

private final Logger logger;

private final ReferenceQueue<ByteBuffer> queue;

private final ReferenceQueueListener listener;

private final Set<DirectBufferWeakReference<ByteBuffer>> enqueueBuffers;

private final Thread workerThread;

public DirectBufferFactory(Logger logger)
{
this.logger = logger;
this.queue = new ReferenceQueue<ByteBuffer>();
this.listener = new ReferenceQueueListener();
this.enqueueBuffers = new HashSet<DirectBufferWeakReference<ByteBuffer>>();
this.workerThread = new Thread(this.listener, "My DirectBuffer Clean Thread");
}

public void startListener()
{
this.workerThread.start();
}

public ByteBuffer create(int capacity)
{
long[] address = new long[1];
ByteBuffer buffer = allocateByteBuffer(capacity, address);
if (buffer != null)
{
DirectBufferWeakReference<ByteBuffer> ref = new DirectBufferWeakReference<ByteBuffer>(buffer, this.queue, address[0]);
enqueueBuffers.add(ref);
}
return buffer;
}

private static native ByteBuffer allocateByteBuffer(int capacity, long[] address);

private static native void freeByteBuffer(long address);
}
15 changes: 14 additions & 1 deletion src/src/com/tns/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public class Platform
private static JsDebugger jsDebugger;

private static DexFactory dexFactory;

private static DirectBufferFactory directBufferFactory;

private final static Comparator<Method> methodComparator = new Comparator<Method>()
{
Expand Down Expand Up @@ -148,7 +150,7 @@ public static void init(Application application, ThreadScheduler threadScheduler
Date lastModDate = new Date(f.lastModified());
logger.write("init time=" + (d.getTime() - lastModDate.getTime()));
}

initialized = true;
}

Expand Down Expand Up @@ -911,6 +913,17 @@ private static Object createArrayHelper(String arrayClassName, int size) throws

return arr;
}

public synchronized static ByteBuffer allocateByteBuffer(int capacity)
{
if (directBufferFactory == null)
{
directBufferFactory = new DirectBufferFactory(logger);
directBufferFactory.startListener();
}
ByteBuffer buffer = directBufferFactory.create(capacity);
return buffer;
}

@RuntimeCallable
private static boolean useGlobalRefs()
Expand Down
Loading