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
2 changes: 1 addition & 1 deletion src/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ LOCAL_MODULE := NativeScript
LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp AssetExtractor.cpp\
com_tns_Runtime.cpp Runtime.cpp \
com_tns_JsDebugger.cpp \
JEnv.cpp DirectBuffer.cpp NativeScriptException.cpp \
JEnv.cpp DirectBuffer.cpp ArrayBufferHelper.cpp NativeScriptException.cpp \
JsDebugger.cpp SimpleAllocator.cpp \
CallbackHandlers.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \
MethodCache.cpp JavaObjectArrayCache.cpp \
Expand Down
115 changes: 115 additions & 0 deletions src/jni/ArrayBufferHelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "ArrayBufferHelper.h"
#include "JEnv.h"
#include "V8GlobalHelpers.h"
#include "NativeScriptException.h"
#include <sstream>


using namespace v8;
using namespace tns;

ArrayBufferHelper::ArrayBufferHelper()
: m_objectManager(nullptr), m_ByteBufferClass(nullptr), m_isDirectMethodID(nullptr)
{
}

void ArrayBufferHelper::CreateConvertFunctions(Isolate *isolate, const Local<Object>& global, ObjectManager *objectManager)
{
m_objectManager = objectManager;

auto extData = External::New(isolate, this);
auto fromFunc = FunctionTemplate::New(isolate, CreateFromCallbackStatic, extData)->GetFunction();
auto ctx = isolate->GetCurrentContext();
auto arrBufferCtorFunc = global->Get(ConvertToV8String("ArrayBuffer")).As<Function>();
arrBufferCtorFunc->Set(ctx, ConvertToV8String("from"), fromFunc);
}

void ArrayBufferHelper::CreateFromCallbackStatic(const FunctionCallbackInfo<Value>& info)
{
try
{
auto extData = info.Data().As<External>();
auto thiz = reinterpret_cast<ArrayBufferHelper*>(extData->Value());
thiz->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 = m_objectManager->GetJavaObjectByJsObject(argObj);

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

JEnv env;

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

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

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

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

auto ret = env.CallBooleanMethod(obj, m_isDirectMethodID);

auto isDirectBuffer = ret == 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);
}
31 changes: 31 additions & 0 deletions src/jni/ArrayBufferHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef ARRAYBUFFERHELPER_H_
#define ARRAYBUFFERHELPER_H_

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

namespace tns
{
class ArrayBufferHelper
{
public:
ArrayBufferHelper();

void CreateConvertFunctions(v8::Isolate *isolate, const v8::Local<v8::Object>& global, ObjectManager *objectManager);

private:

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

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

ObjectManager *m_objectManager;

jclass m_ByteBufferClass;

jmethodID m_isDirectMethodID;
};
}


#endif /* ARRAYBUFFERHELPER_H_ */
39 changes: 39 additions & 0 deletions src/jni/NativePlatform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef NATIVEPLATFORM_H_
#define NATIVEPLATFORM_H_

#include "v8.h"
#include "JniLocalRef.h"
#include "ObjectManager.h"
#include "SimpleAllocator.h"
#include "ArrayBufferHelper.h"

jobject ConvertJsValueToJavaObject(tns::JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);

namespace tns
{
class NativePlatform
{
public:
static void Init(JavaVM *vm, void *reserved);
static v8::Isolate* InitNativeScript(JNIEnv *_env, jobject obj, jstring filesPath, jboolean verboseLoggingEnabled, jstring packageName, jobjectArray args, jobject jsDebugger);
static void RunModule(JNIEnv *_env, jobject obj, jstring scriptFile);
static jobject RunScript(JNIEnv *_env, jobject obj, jstring scriptFile);
static jobject CallJSMethodNative(JNIEnv *_env, jobject obj, jint javaObjectID, jstring methodName, jint retType, jboolean isConstructor, jobjectArray packagedArgs);
static void CreateJSInstanceNative(JNIEnv *_env, jobject obj, jobject javaObject, jint javaObjectID, jstring className);
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);

bool LogEnabled = true;
private:

static v8::Isolate* PrepareV8Runtime(JEnv& env, const std::string& filesPath, jstring packageName, jobject jsDebugger);
static jobject ConvertJsValueToJavaObject(JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);

static v8::Isolate *s_isolate;

static ArrayBufferHelper s_arrayBufferHeper;
};
}

#endif /*#ifndef NATIVEPLATFORM_H_*/
3 changes: 2 additions & 1 deletion src/jni/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName,

ArrayHelper::Init(context);

m_arrayBufferHelper.CreateConvertFunctions(isolate, global, m_objectManager);

return isolate;
}

Expand Down Expand Up @@ -494,4 +496,3 @@ void Runtime::PrepareExtendFunction(Isolate *isolate, jstring filesPath)
JavaVM* Runtime::s_jvm = nullptr;
map<int, Runtime*> Runtime::s_id2RuntimeCache;
map<Isolate*, Runtime*> Runtime::s_isolate2RuntimesCache;

3 changes: 3 additions & 0 deletions src/jni/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ObjectManager.h"
#include "SimpleAllocator.h"
#include "WeakRef.h"
#include "ArrayBufferHelper.h"
#include "Profiler.h"

jobject ConvertJsValueToJavaObject(tns::JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
Expand Down Expand Up @@ -50,6 +51,8 @@ namespace tns

ObjectManager *m_objectManager;

ArrayBufferHelper m_arrayBufferHelper;

WeakRef m_weakRef;

Profiler m_profiler;
Expand Down
1 change: 1 addition & 0 deletions test-app/assets/app/mainpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ require("./tests/testNativeModules");
require("./tests/requireExceptionTests");
require("./tests/java-array-test");
require("./tests/field-access-test");
require("./tests/byte-buffer-test");
require("./tests/dex-interface-implementation");
52 changes: 52 additions & 0 deletions test-app/assets/app/tests/byte-buffer-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
describe("Tests mapped ByteBuffer conversion", function () {
it("should convert ByteBuffer to ArrayBuffer", function () {
var bb = java.nio.ByteBuffer.allocateDirect(12);
var ab = ArrayBuffer.from(bb);
var int8arr = new Int8Array(ab);
expect(int8arr.length).toBe(12);
var int32arr = new Int32Array(ab);
expect(int32arr.length).toBe(3);
});

it("should share the same memory of all typed arrays", function () {
var bb = java.nio.ByteBuffer.allocateDirect(12);
var ab = ArrayBuffer.from(bb);
var int8arr = new Int8Array(ab);
expect(int8arr.length).toBe(12);
var int32arr = new Int32Array(ab);
expect(int32arr.length).toBe(3);
int8arr[0] = 0x11;
int8arr[1] = 0x22;
int8arr[2] = 0x33;
int8arr[3] = 0x44;
var value = int32arr[0];
expect(value).toBe(0x44332211);
});

it("should keep original ByteBuffer after conversion", function () {
var bb = java.nio.ByteBuffer.allocateDirect(12);
var ab = ArrayBuffer.from(bb);
var same = bb === ab.nativeObject;
expect(same).toBe(true);
});

it("should throw exception when ArrayBuffer.from is called with wrong number of arguments", function () {
var exceptionCaught = false;
try {
var ab = ArrayBuffer.from(1, 2);
} catch(e) {
exceptionCaught = true
}
expect(exceptionCaught).toBe(true);
});

it("should throw exception when ArrayBuffer.from is called with wrong argument type", function () {
var exceptionCaught = false;
try {
var ab = ArrayBuffer.from({});
} catch(e) {
exceptionCaught = true
}
expect(exceptionCaught).toBe(true);
});
});