Skip to content

Commit a0f5d11

Browse files
author
Mihail Slavchev
committed
Merge pull request #379 from NativeScript/slavchev/bytebuffer-support
add support for ByteBuffer to ArrayBuffer conversion
2 parents 23e1593 + c69eb03 commit a0f5d11

File tree

8 files changed

+244
-2
lines changed

8 files changed

+244
-2
lines changed

src/jni/Android.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ LOCAL_MODULE := NativeScript
6565
LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp AssetExtractor.cpp\
6666
com_tns_Runtime.cpp Runtime.cpp \
6767
com_tns_JsDebugger.cpp \
68-
JEnv.cpp DirectBuffer.cpp NativeScriptException.cpp \
68+
JEnv.cpp DirectBuffer.cpp ArrayBufferHelper.cpp NativeScriptException.cpp \
6969
JsDebugger.cpp SimpleAllocator.cpp \
7070
CallbackHandlers.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \
7171
MethodCache.cpp JavaObjectArrayCache.cpp \

src/jni/ArrayBufferHelper.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "ArrayBufferHelper.h"
2+
#include "JEnv.h"
3+
#include "V8GlobalHelpers.h"
4+
#include "NativeScriptException.h"
5+
#include <sstream>
6+
7+
8+
using namespace v8;
9+
using namespace tns;
10+
11+
ArrayBufferHelper::ArrayBufferHelper()
12+
: m_objectManager(nullptr), m_ByteBufferClass(nullptr), m_isDirectMethodID(nullptr)
13+
{
14+
}
15+
16+
void ArrayBufferHelper::CreateConvertFunctions(Isolate *isolate, const Local<Object>& global, ObjectManager *objectManager)
17+
{
18+
m_objectManager = objectManager;
19+
20+
auto extData = External::New(isolate, this);
21+
auto fromFunc = FunctionTemplate::New(isolate, CreateFromCallbackStatic, extData)->GetFunction();
22+
auto ctx = isolate->GetCurrentContext();
23+
auto arrBufferCtorFunc = global->Get(ConvertToV8String("ArrayBuffer")).As<Function>();
24+
arrBufferCtorFunc->Set(ctx, ConvertToV8String("from"), fromFunc);
25+
}
26+
27+
void ArrayBufferHelper::CreateFromCallbackStatic(const FunctionCallbackInfo<Value>& info)
28+
{
29+
try
30+
{
31+
auto extData = info.Data().As<External>();
32+
auto thiz = reinterpret_cast<ArrayBufferHelper*>(extData->Value());
33+
thiz->CreateFromCallbackImpl(info);
34+
}
35+
catch (NativeScriptException& e)
36+
{
37+
e.ReThrowToV8();
38+
}
39+
catch (std::exception e) {
40+
std::stringstream ss;
41+
ss << "Error: c++ exception: " << e.what() << std::endl;
42+
NativeScriptException nsEx(ss.str());
43+
nsEx.ReThrowToV8();
44+
}
45+
catch (...) {
46+
NativeScriptException nsEx(std::string("Error: c++ exception!"));
47+
nsEx.ReThrowToV8();
48+
}
49+
}
50+
51+
void ArrayBufferHelper::CreateFromCallbackImpl(const FunctionCallbackInfo<Value>& info)
52+
{
53+
auto isolate = info.GetIsolate();
54+
auto len = info.Length();
55+
56+
if (len != 1)
57+
{
58+
throw NativeScriptException("Wrong number of arguments (1 expected)");
59+
}
60+
61+
auto arg = info[0];
62+
63+
if (!arg->IsObject())
64+
{
65+
throw NativeScriptException("Wrong type of argument (object expected)");
66+
}
67+
68+
auto argObj = arg.As<Object>();
69+
70+
auto obj = m_objectManager->GetJavaObjectByJsObject(argObj);
71+
72+
if (obj.IsNull())
73+
{
74+
throw NativeScriptException("Wrong type of argument (object expected)");
75+
}
76+
77+
JEnv env;
78+
79+
if (m_ByteBufferClass == nullptr)
80+
{
81+
m_ByteBufferClass = env.FindClass("java/nio/ByteBuffer");
82+
assert(m_ByteBufferClass != nullptr);
83+
}
84+
85+
auto isByteBuffer = env.IsInstanceOf(obj, m_ByteBufferClass);
86+
87+
if (!isByteBuffer)
88+
{
89+
throw NativeScriptException("Wrong type of argument (ByteBuffer expected)");
90+
}
91+
92+
if (m_isDirectMethodID == nullptr)
93+
{
94+
m_isDirectMethodID = env.GetMethodID(m_ByteBufferClass, "isDirect", "()Z");
95+
assert(m_isDirectMethodID != nullptr);
96+
}
97+
98+
auto ret = env.CallBooleanMethod(obj, m_isDirectMethodID);
99+
100+
auto isDirectBuffer = ret == JNI_TRUE;
101+
102+
if (!isDirectBuffer)
103+
{
104+
throw NativeScriptException("Direct ByteBuffer expected)");
105+
}
106+
107+
auto data = env.GetDirectBufferAddress(obj);
108+
auto size = env.GetDirectBufferCapacity(obj);
109+
110+
auto arrayBuffer = ArrayBuffer::New(isolate, data, size);
111+
auto ctx = isolate->GetCurrentContext();
112+
arrayBuffer->Set(ctx, ConvertToV8String("nativeObject"), argObj);
113+
114+
info.GetReturnValue().Set(arrayBuffer);
115+
}

src/jni/ArrayBufferHelper.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef ARRAYBUFFERHELPER_H_
2+
#define ARRAYBUFFERHELPER_H_
3+
4+
#include "v8.h"
5+
#include "ObjectManager.h"
6+
7+
namespace tns
8+
{
9+
class ArrayBufferHelper
10+
{
11+
public:
12+
ArrayBufferHelper();
13+
14+
void CreateConvertFunctions(v8::Isolate *isolate, const v8::Local<v8::Object>& global, ObjectManager *objectManager);
15+
16+
private:
17+
18+
static void CreateFromCallbackStatic(const v8::FunctionCallbackInfo<v8::Value>& info);
19+
20+
void CreateFromCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info);
21+
22+
ObjectManager *m_objectManager;
23+
24+
jclass m_ByteBufferClass;
25+
26+
jmethodID m_isDirectMethodID;
27+
};
28+
}
29+
30+
31+
#endif /* ARRAYBUFFERHELPER_H_ */

src/jni/NativePlatform.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef NATIVEPLATFORM_H_
2+
#define NATIVEPLATFORM_H_
3+
4+
#include "v8.h"
5+
#include "JniLocalRef.h"
6+
#include "ObjectManager.h"
7+
#include "SimpleAllocator.h"
8+
#include "ArrayBufferHelper.h"
9+
10+
jobject ConvertJsValueToJavaObject(tns::JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
11+
12+
namespace tns
13+
{
14+
class NativePlatform
15+
{
16+
public:
17+
static void Init(JavaVM *vm, void *reserved);
18+
static v8::Isolate* InitNativeScript(JNIEnv *_env, jobject obj, jstring filesPath, jboolean verboseLoggingEnabled, jstring packageName, jobjectArray args, jobject jsDebugger);
19+
static void RunModule(JNIEnv *_env, jobject obj, jstring scriptFile);
20+
static jobject RunScript(JNIEnv *_env, jobject obj, jstring scriptFile);
21+
static jobject CallJSMethodNative(JNIEnv *_env, jobject obj, jint javaObjectID, jstring methodName, jint retType, jboolean isConstructor, jobjectArray packagedArgs);
22+
static void CreateJSInstanceNative(JNIEnv *_env, jobject obj, jobject javaObject, jint javaObjectID, jstring className);
23+
static jint GenerateNewObjectId(JNIEnv *env, jobject obj);
24+
static void AdjustAmountOfExternalAllocatedMemoryNative(JNIEnv *env, jobject obj, jlong usedMemory);
25+
static void PassUncaughtExceptionToJsNative(JNIEnv *env, jobject obj, jthrowable exception, jstring stackTrace);
26+
27+
bool LogEnabled = true;
28+
private:
29+
30+
static v8::Isolate* PrepareV8Runtime(JEnv& env, const std::string& filesPath, jstring packageName, jobject jsDebugger);
31+
static jobject ConvertJsValueToJavaObject(JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
32+
33+
static v8::Isolate *s_isolate;
34+
35+
static ArrayBufferHelper s_arrayBufferHeper;
36+
};
37+
}
38+
39+
#endif /*#ifndef NATIVEPLATFORM_H_*/

src/jni/Runtime.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName,
434434

435435
ArrayHelper::Init(context);
436436

437+
m_arrayBufferHelper.CreateConvertFunctions(isolate, global, m_objectManager);
438+
437439
return isolate;
438440
}
439441

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

src/jni/Runtime.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ObjectManager.h"
77
#include "SimpleAllocator.h"
88
#include "WeakRef.h"
9+
#include "ArrayBufferHelper.h"
910
#include "Profiler.h"
1011

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

5152
ObjectManager *m_objectManager;
5253

54+
ArrayBufferHelper m_arrayBufferHelper;
55+
5356
WeakRef m_weakRef;
5457

5558
Profiler m_profiler;

test-app/assets/app/mainpage.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ require("./tests/testNativeModules");
4242
require("./tests/requireExceptionTests");
4343
require("./tests/java-array-test");
4444
require("./tests/field-access-test");
45+
require("./tests/byte-buffer-test");
4546
require("./tests/dex-interface-implementation");
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
describe("Tests mapped ByteBuffer conversion", function () {
2+
it("should convert ByteBuffer to ArrayBuffer", function () {
3+
var bb = java.nio.ByteBuffer.allocateDirect(12);
4+
var ab = ArrayBuffer.from(bb);
5+
var int8arr = new Int8Array(ab);
6+
expect(int8arr.length).toBe(12);
7+
var int32arr = new Int32Array(ab);
8+
expect(int32arr.length).toBe(3);
9+
});
10+
11+
it("should share the same memory of all typed arrays", function () {
12+
var bb = java.nio.ByteBuffer.allocateDirect(12);
13+
var ab = ArrayBuffer.from(bb);
14+
var int8arr = new Int8Array(ab);
15+
expect(int8arr.length).toBe(12);
16+
var int32arr = new Int32Array(ab);
17+
expect(int32arr.length).toBe(3);
18+
int8arr[0] = 0x11;
19+
int8arr[1] = 0x22;
20+
int8arr[2] = 0x33;
21+
int8arr[3] = 0x44;
22+
var value = int32arr[0];
23+
expect(value).toBe(0x44332211);
24+
});
25+
26+
it("should keep original ByteBuffer after conversion", function () {
27+
var bb = java.nio.ByteBuffer.allocateDirect(12);
28+
var ab = ArrayBuffer.from(bb);
29+
var same = bb === ab.nativeObject;
30+
expect(same).toBe(true);
31+
});
32+
33+
it("should throw exception when ArrayBuffer.from is called with wrong number of arguments", function () {
34+
var exceptionCaught = false;
35+
try {
36+
var ab = ArrayBuffer.from(1, 2);
37+
} catch(e) {
38+
exceptionCaught = true
39+
}
40+
expect(exceptionCaught).toBe(true);
41+
});
42+
43+
it("should throw exception when ArrayBuffer.from is called with wrong argument type", function () {
44+
var exceptionCaught = false;
45+
try {
46+
var ab = ArrayBuffer.from({});
47+
} catch(e) {
48+
exceptionCaught = true
49+
}
50+
expect(exceptionCaught).toBe(true);
51+
});
52+
});

0 commit comments

Comments
 (0)