Skip to content

Commit

Permalink
classlib: refactor nio buffers implementation so that they wrap typed…
Browse files Browse the repository at this point in the history
… arrays in JS

Fix #990
  • Loading branch information
konsoletyper committed Jan 26, 2025
1 parent 13e7cc9 commit a6d992c
Show file tree
Hide file tree
Showing 69 changed files with 4,503 additions and 562 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
args+=("-Pteavm.localNodeJS=true")
echo "${args[@]}"
./gradlew "${args[@]}" test
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: failure()
with:
name: "test-reports-${{ matrix.platform }}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ public static int reverse(int i) {

public static int reverseBytes(int i) {
i = ((i & 0xFF00FF00) >>> 8) | ((i & 0x00FF00FF) << 8);
i = (i >>> 16) + (i << 16);
i = (i >>> 16) | (i << 16);
return i;
}

Expand Down
16 changes: 7 additions & 9 deletions classlib/src/main/java/org/teavm/classlib/java/nio/TBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@
package org.teavm.classlib.java.nio;

public abstract class TBuffer {
int capacity;
int position;
int limit;
int mark = -1;

TBuffer(int capacity) {
this.capacity = capacity;
limit = capacity;
TBuffer() {
}

public final int capacity() {
return capacity;
return capacityImpl();
}

abstract int capacityImpl();

public final int position() {
return position;
}
Expand All @@ -51,9 +50,8 @@ public final int limit() {
}

public TBuffer limit(int newLimit) {
if (newLimit < 0 || newLimit > capacity) {
throw new IllegalArgumentException("New limit " + newLimit + " is outside of range [0;"
+ capacity + "]");
if (newLimit < 0 || newLimit > capacity()) {
throw new IllegalArgumentException();
}
if (mark > newLimit) {
mark = -1;
Expand All @@ -80,7 +78,7 @@ public TBuffer reset() {

public TBuffer clear() {
position = 0;
limit = capacity;
limit = capacity();
mark = -1;
return this;
}
Expand Down
148 changes: 95 additions & 53 deletions classlib/src/main/java/org/teavm/classlib/java/nio/TByteBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,52 @@
*/
package org.teavm.classlib.java.nio;

import java.nio.BufferUnderflowException;
import java.util.Objects;
import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.java.lang.TComparable;
import org.teavm.jso.typedarrays.Int8Array;

public abstract class TByteBuffer extends TBuffer implements TComparable<TByteBuffer> {
int start;
byte[] array;
TByteOrder order = TByteOrder.BIG_ENDIAN;

TByteBuffer(int start, int capacity, byte[] array, int position, int limit) {
super(capacity);
this.start = start;
this.array = array;
this.position = position;
this.limit = limit;
TByteBuffer() {
}

public static TByteBuffer allocateDirect(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Capacity is negative: " + capacity);
}
if (PlatformDetector.isJavaScript()) {
var result = new TByteBufferJsImpl(null, 0, new Int8Array(capacity), true, false);
result.limit = capacity;
return result;
}
return new TByteBufferImpl(capacity, true);
}

public static TByteBuffer allocate(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Capacity is negative: " + capacity);
}
if (PlatformDetector.isJavaScript()) {
var array = new byte[capacity];
var result = new TByteBufferJsImpl(array, 0, Int8Array.fromJavaArray(array), false, false);
result.limit = capacity;
return result;
}
return new TByteBufferImpl(capacity, false);
}

public static TByteBuffer wrap(byte[] array, int offset, int length) {
Objects.checkFromIndexSize(offset, length, array.length);
if (PlatformDetector.isJavaScript()) {
var data = Int8Array.fromJavaArray(array);
var result = new TByteBufferJsImpl(array, 0, data, false, false);
result.position = offset;
result.limit = offset + length;
return result;
}
return new TByteBufferImpl(0, array.length, array, offset, offset + length, false, false);
}

Expand All @@ -69,59 +83,65 @@ public static TByteBuffer wrap(byte[] array) {
public abstract TByteBuffer put(int index, byte b);

public TByteBuffer get(byte[] dst, int offset, int length) {
if (offset < 0 || offset > dst.length) {
throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + dst.length + ")");
}
if (offset + length > dst.length) {
throw new IndexOutOfBoundsException("The last byte in dst " + (offset + length) + " is outside "
+ "of array of size " + dst.length);
}
if (remaining() < length) {
throw new TBufferUnderflowException();
if (length < 0 || offset < 0 || offset + length > dst.length) {
throw new IndexOutOfBoundsException();
}
if (length < 0) {
throw new IndexOutOfBoundsException("Length " + length + " must be non-negative");
}
int pos = position + start;
for (int i = 0; i < length; ++i) {
dst[offset++] = array[pos++];
if (length > remaining()) {
throw new BufferUnderflowException();
}
getImpl(position, dst, offset, length);
position += length;
return this;
}

public TByteBuffer get(int index, byte[] dst, int offset, int length) {
if (length < 0 || offset < 0 || offset + length > dst.length || index < 0 || index + length > limit()) {
throw new IndexOutOfBoundsException();
}
getImpl(index, dst, offset, length);
return this;
}

abstract void getImpl(int index, byte[] dst, int offset, int length);

public TByteBuffer get(byte[] dst) {
return get(dst, 0, dst.length);
}

public TByteBuffer put(TByteBuffer src) {
return put(src.array, src.start + src.position, src.remaining());
return put(position(), src, src.position(), src.remaining());
}

public TByteBuffer put(byte[] src, int offset, int length) {
if (length == 0) {
public TByteBuffer put(int index, TByteBuffer src, int offset, int length) {
if (src.remaining() == 0) {
return this;
}
if (isReadOnly()) {
throw new TReadOnlyBufferException();
}
if (remaining() < length) {
throw new TBufferOverflowException();
if (length < 0 || offset < 0 || offset + length > src.limit() || index < 0 || index + length > limit()) {
throw new IndexOutOfBoundsException();
}
if (offset < 0 || offset > src.length) {
throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + src.length + ")");
putImpl(index, src, offset, length);
return this;
}

abstract void putImpl(int index, TByteBuffer src, int offset, int length);

public TByteBuffer put(byte[] src, int offset, int length) {
if (length == 0) {
return this;
}
if (offset + length > src.length) {
throw new IndexOutOfBoundsException("The last byte in src " + (offset + length) + " is outside "
+ "of array of size " + src.length);
if (isReadOnly()) {
throw new TReadOnlyBufferException();
}
if (length < 0) {
throw new IndexOutOfBoundsException("Length " + length + " must be non-negative");
if (length < 0 || offset < 0 || offset + length > src.length) {
throw new IndexOutOfBoundsException();
}
int pos = position + start;
for (int i = 0; i < length; ++i) {
array[pos++] = src[offset++];
if (length > remaining()) {
throw new TBufferOverflowException();
}
putImpl(src, offset, position, length);
position += length;
return this;
}
Expand All @@ -130,38 +150,60 @@ public final TByteBuffer put(byte[] src) {
return put(src, 0, src.length);
}

public TByteBuffer put(int index, byte[] src, int offset, int length) {
if (length == 0) {
return this;
}
if (isReadOnly()) {
throw new TReadOnlyBufferException();
}
if (length < 0 || offset < 0 || offset + length > src.length || index < 0 || index + length > limit()) {
throw new IndexOutOfBoundsException();
}
putImpl(src, offset, length, length);
return this;
}

abstract void putImpl(byte[] src, int srcOffset, int destOffset, int length);

@Override
public boolean hasArray() {
return true;
public final boolean hasArray() {
return hasArrayImpl();
}

@Override
public final byte[] array() {
return array;
return arrayImpl();
}

@Override
public int arrayOffset() {
return start;
public final int arrayOffset() {
return arrayOffsetImpl();
}

abstract boolean hasArrayImpl();

abstract byte[] arrayImpl();

abstract int arrayOffsetImpl();

public abstract TByteBuffer compact();

@Override
public abstract boolean isDirect();

@Override
public String toString() {
return "[ByteBuffer position=" + position + ", limit=" + limit + ", capacity=" + capacity + ", mark "
return "[ByteBuffer position=" + position + ", limit=" + limit + ", capacity=" + capacity() + ", mark "
+ (mark >= 0 ? " at " + mark : " is not set") + "]";
}

@Override
public int hashCode() {
int hashCode = 0;
int pos = position + start;
for (int i = position; i < limit; ++i) {
hashCode = 31 * hashCode + array[pos++];
int pos = position();
for (int i = position(); i < limit; ++i) {
hashCode = 31 * hashCode + get(pos);
}
return hashCode;
}
Expand All @@ -179,10 +221,10 @@ public boolean equals(Object obj) {
if (sz != other.remaining()) {
return false;
}
int a = position + start;
int b = other.position + other.start;
int a = position();
int b = other.position();
for (int i = 0; i < sz; ++i) {
if (array[a++] != other.array[b++]) {
if (get(a++) != other.get(b++)) {
return false;
}
}
Expand All @@ -195,10 +237,10 @@ public int compareTo(TByteBuffer other) {
return 0;
}
int sz = Math.min(remaining(), other.remaining());
int a = position + start;
int b = other.position + other.start;
int a = position();
int b = other.position();
for (int i = 0; i < sz; ++i) {
int r = Byte.compare(array[a++], other.array[b++]);
int r = Byte.compare(get(a++), other.get(b++));
if (r != 0) {
return r;
}
Expand Down
Loading

0 comments on commit a6d992c

Please sign in to comment.