Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c9701d3aa793
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2dd196113143
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Oct 21, 2015

  1. Copy the full SHA
    7ed6f37 View commit details
  2. tune seekable byte[] channel impl to fallback in limited envs (as sug…

    …gested in #3337)
    
    ... also keep the fields needed to avoid constant lookup in ByteArrayInputStream.class
    kares committed Oct 21, 2015
    Copy the full SHA
    2dd1961 View commit details
Showing with 56 additions and 28 deletions.
  1. +4 −2 core/src/main/java/org/jruby/util/io/ChannelHelper.java
  2. +52 −26 core/src/main/java/org/jruby/util/io/SeekableByteChannelImpl.java
6 changes: 4 additions & 2 deletions core/src/main/java/org/jruby/util/io/ChannelHelper.java
Original file line number Diff line number Diff line change
@@ -26,8 +26,10 @@ public abstract class ChannelHelper {
private ChannelHelper() { /* */ }

public static ReadableByteChannel readableChannel(final InputStream inputStream) {
if (inputStream instanceof ByteArrayInputStream) {
return new SeekableByteChannelImpl((ByteArrayInputStream) inputStream);
if ( inputStream instanceof ByteArrayInputStream ) {
if ( SeekableByteChannelImpl.USABLE ) {
return new SeekableByteChannelImpl((ByteArrayInputStream) inputStream);
}
}
return Channels.newChannel(inputStream);
}
78 changes: 52 additions & 26 deletions core/src/main/java/org/jruby/util/io/SeekableByteChannelImpl.java
Original file line number Diff line number Diff line change
@@ -22,13 +22,10 @@
* Seekable byte channel impl over a byte array stream.
* @author kares
*/
final class SeekableByteChannelImpl extends AbstractInterruptibleChannel // Not really interruptible
final class SeekableByteChannelImpl extends AbstractInterruptibleChannel
implements ReadableByteChannel, SeekableByteChannel {

private static final byte[] EMPTY_BUF = new byte[0];

private final ByteArrayInputStream in;
private byte buf[] = EMPTY_BUF;

private final int mark;
private final int count;
@@ -37,8 +34,8 @@ final class SeekableByteChannelImpl extends AbstractInterruptibleChannel // Not

SeekableByteChannelImpl(ByteArrayInputStream in) {
this.in = in;
this.mark = ByteArrayInputStreamHelper.mark(in);
this.count = ByteArrayInputStreamHelper.count(in);
this.mark = mark(in);
this.count = count(in);
}

@Override
@@ -71,7 +68,7 @@ public synchronized int read(ByteBuffer target) throws IOException {
// SeekableByteChannel interface :

public long position() {
return ByteArrayInputStreamHelper.pos(in) - mark;
return pos(in) - mark;
}

public synchronized SeekableByteChannel position(long newPosition) throws IOException {
@@ -104,32 +101,61 @@ public int write(ByteBuffer src) throws IOException {
throw new UnsupportedOperationException("write not supported");
}

private static class ByteArrayInputStreamHelper {
// static helpers

static int pos(ByteArrayInputStream in) {
return readField(in, "pos"); // current pos
}
private static int pos(ByteArrayInputStream in) {
return readIntField(in, posField); // current pos
}

static int count(ByteArrayInputStream in) {
return readField(in, "count"); // buf.length or offset + length
}
private static int count(ByteArrayInputStream in) {
return readIntField(in, countField); // buf.length or offset + length
}

static int mark(ByteArrayInputStream in) {
return readField(in, "mark"); // 0 oir offset or if marked previously
private static int mark(ByteArrayInputStream in) {
return readIntField(in, markField); // 0 or offset or if marked previously
}

private static int readIntField(ByteArrayInputStream self, Field field) {
try {
return field.getInt(self);
}
catch (IllegalAccessException ex) {
// fields are set-accessible thus should not happen
throw new IllegalStateException(ex);
}
}

static final boolean USABLE;

private static final Field posField;
private static final Field countField;
private static final Field markField;

private static int readField(ByteArrayInputStream self, String name) {
try {
Field field = ByteArrayInputStream.class.getDeclaredField(name);
field.setAccessible(true);
return field.getInt(self);
}
catch (NoSuchFieldException ex) { throw new RuntimeException(ex); } // should never happen
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex); // TODO
}
static {
posField = accessibleField("pos");
if (posField != null) {
countField = accessibleField("count");
markField = accessibleField("mark");
USABLE = true;
}
else {
countField = markField = null;
USABLE = false;
}
}

private static Field accessibleField(final String name) {
try {
Field field = ByteArrayInputStream.class.getDeclaredField(name);
field.setAccessible(true);
return field;
}
catch (NoSuchFieldException ex) {
return null; // should never happen
}
catch (SecurityException ex) {
return null;
}
}

}