Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Implement efficient access to java.nio.ByteBuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
brianquinlan committed Sep 7, 2023
1 parent b845ff1 commit 268f843
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
23 changes: 23 additions & 0 deletions jni/lib/src/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data' as typed_data;

import 'package:ffi/ffi.dart';
import 'package:path/path.dart';
Expand Down Expand Up @@ -350,6 +351,28 @@ extension AdditionalEnvMethods on GlobalJniEnv {
return result;
}

typed_data.Uint8List _asUInt8List(JObjectPtr jbuf) {
final addr = GetDirectBufferAddress(jbuf);
if (addr == nullptr) {
throw ArgumentError();
}

final capacity = GetDirectBufferCapacity(jbuf);
if (capacity == -1) {
throw ArgumentError();
}

return addr.cast<Uint8>().asTypedList(capacity);
}

typed_data.Uint8List asUInt8List(JObjectPtr jbuf, [int start = 0, int? end]) {
return _asUInt8List(jbuf).sublist(start, end);
}

void setRange(JObjectPtr jbuf, List<int> l, int start, int end) {
_asUInt8List(jbuf).setRange(start, end, l);
}

/// Returns a new [JStringPtr] from contents of [s].
JStringPtr toJStringPtr(String s) => using((arena) {
final utf = s.toNativeUtf16(allocator: arena).cast<Uint16>();
Expand Down
1 change: 1 addition & 0 deletions jni/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies:

dev_dependencies:
## Pin ffigen version because we are depending on internal APIs.
benchmarking: ^0.6.1
ffigen: 8.0.2
flutter_lints: ^2.0.0
test: ^1.21.1
Expand Down
51 changes: 51 additions & 0 deletions jni/test/global_env_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';
import 'dart:typed_data';

import 'package:benchmarking/benchmarking.dart';
import 'package:jni/jni.dart';
import 'package:jni/src/jvalues.dart';
import 'package:test/test.dart';
Expand All @@ -12,6 +14,34 @@ import 'test_util/test_util.dart';

const maxLongInJava = 9223372036854775807;

abstract class A extends SyncBenchmark {
late JObject buffer;
@override
void setup() {
buffer = Jni.invokeStaticMethod<JObject>("java/nio/ByteBuffer",
'allocateDirect', '(I)Ljava/nio/ByteBuffer;', [JValueInt(1000000)]);
}
}

class B extends A {
@override
void run() {
Jni.env.asUInt8List(buffer.reference);
}
}

class C extends A {
@override
void run() {
final length = buffer.callMethodByName<int>('capacity', '()I', []);

final l = Uint8List(length);
for (var i = 0; i < length; ++i) {
l[i] = buffer.callMethodByName<int>('get', '(I)B', [JValueInt(i)]);
}
}
}

void main() {
// Running on Android through flutter, this plugin
// will bind to Android runtime's JVM.
Expand All @@ -28,6 +58,8 @@ void main() {
checkDylibIsUpToDate();
Jni.spawnIfNotExists(dylibDir: "build/jni_libs", jvmOptions: ["-Xmx128m"]);
}
B().measure().report();
C().measure().report();
run(testRunner: test);
}

Expand All @@ -50,6 +82,25 @@ void run({required TestRunnerCallback testRunner}) {
Jni.initDLApi();
});

testRunner('test', () {
final m = Jni.invokeStaticMethod<JObject>("java/nio/ByteBuffer",
'allocateDirect', '(I)Ljava/nio/ByteBuffer;', [JValueInt(4)]);

m.callMethodByName<JObject>(
'put', '(IB)Ljava/nio/ByteBuffer;', [JValueInt(2), JValueByte(29)]);
expect(Jni.env.asUInt8List(m.reference), equals([0, 0, 29, 0]));
});

testRunner('test2', () {
final m = Jni.invokeStaticMethod<JObject>("java/nio/ByteBuffer",
'allocateDirect', '(I)Ljava/nio/ByteBuffer;', [JValueInt(4)]);

m.callMethodByName<JObject>(
'put', '(IB)Ljava/nio/ByteBuffer;', [JValueInt(2), JValueByte(29)]);
Jni.env.setRange(m.reference, [1, 2, 3], 0, 2);
expect(Jni.env.asUInt8List(m.reference), equals([1, 2, 29, 0]));
});

testRunner('get JNI Version', () {
expect(Jni.env.GetVersion(), isNot(equals(0)));
});
Expand Down

0 comments on commit 268f843

Please sign in to comment.