diff --git a/ext/java/org/jruby/ext/stringio/StringIO.java b/ext/java/org/jruby/ext/stringio/StringIO.java index f3ab1cf..9c58077 100644 --- a/ext/java/org/jruby/ext/stringio/StringIO.java +++ b/ext/java/org/jruby/ext/stringio/StringIO.java @@ -79,27 +79,17 @@ import static org.jruby.util.RubyStringBuilder.types; @JRubyClass(name="StringIO") @SuppressWarnings("serial") public class StringIO extends RubyObject implements EncodingCapable, DataType { - static class StringIOData { - /** - * ATTN: the value of internal might be reset to null - * (during StringIO.open with block), so watch out for that. - */ - RubyString string; - Encoding enc; - int pos; - int lineno; - int flags; - volatile Object owner; - } - private StringIOData ptr; - private byte flags; + private RubyString string; + private Encoding enc; + private int pos; + private int lineno; + private int flags; + private volatile Object owner; + private StringIO ptr; + + private byte strioFlags; // MRI: get_strio, StringIO macro - private StringIOData getPtr() { - // equivalent to rb_io_taint_check without tainting - checkFrozen(); - return ptr; - } private static final String STRINGIO_VERSION = "3.1.10"; @@ -108,7 +98,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { private static final byte STRIO_WRITABLE = 2; private static final byte STRIO_READWRITE = (STRIO_READABLE | STRIO_WRITABLE); - private static final AtomicReferenceFieldUpdater LOCKED_UPDATER = AtomicReferenceFieldUpdater.newUpdater(StringIOData.class, Object.class, "owner"); + private static final AtomicReferenceFieldUpdater LOCKED_UPDATER = AtomicReferenceFieldUpdater.newUpdater(StringIO.class, Object.class, "owner"); private static final ThreadLocal VMODE_VPERM_TL = ThreadLocal.withInitial(() -> EncodingUtils.vmodeVperm(null, null)); private static final ThreadLocal FMODE_TL = ThreadLocal.withInitial(() -> new int[]{0}); @@ -143,13 +133,13 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { // mri: get_enc public Encoding getEncoding() { - StringIOData ptr = this.getPtr(); - Encoding enc = ptr.enc; + checkFrozen(); + Encoding enc = this.enc; if (enc != null) { return enc; } - RubyString string = ptr.string; + RubyString string = this.string; if (string != null) { return string.getEncoding(); } @@ -158,7 +148,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } public void setEncoding(Encoding enc) { - getPtr().enc = enc; + checkFrozen(); + StringIO stringIO = ptr; + stringIO.enc = enc; } @JRubyMethod(name = "new", rest = true, meta = true) @@ -258,7 +250,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { try { val = block.yield(context, strio); } finally { - strio.getPtr().string = null; + strio.checkFrozen(); + strio.ptr.string = null; strio.flags &= ~STRIO_READWRITE; } } @@ -272,8 +265,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(visibility = PRIVATE, keywords = true) public IRubyObject initialize(ThreadContext context) { - if (getPtr() == null) { - ptr = new StringIOData(); + checkFrozen(); + if (ptr == null) { + ptr = this; } // does not dispatch quite right and is not really necessary for us @@ -284,8 +278,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(visibility = PRIVATE, keywords = true) public IRubyObject initialize(ThreadContext context, IRubyObject arg0) { - if (getPtr() == null) { - ptr = new StringIOData(); + checkFrozen(); + if (ptr == null) { + ptr = this; } // does not dispatch quite right and is not really necessary for us @@ -296,8 +291,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(visibility = PRIVATE, keywords = true) public IRubyObject initialize(ThreadContext context, IRubyObject arg0, IRubyObject arg1) { - if (getPtr() == null) { - ptr = new StringIOData(); + checkFrozen(); + if (ptr == null) { + ptr = this; } // does not dispatch quite right and is not really necessary for us @@ -308,8 +304,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(visibility = PRIVATE, keywords = true) public IRubyObject initialize(ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) { - if (getPtr() == null) { - ptr = new StringIOData(); + checkFrozen(); + if (ptr == null) { + ptr = this; } // does not dispatch quite right and is not really necessary for us @@ -324,7 +321,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { IRubyObject string = context.nil; IRubyObject vmode = context.nil; - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { @@ -362,7 +359,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { // switch to per-use oflags if it is ever used in the future EncodingUtils.extractModeEncoding(context, ioEncodable, vmodeAndVpermP, maybeOptions, OFLAGS_UNUSED, fmode); - ptr.flags = fmode[0]; + this.flags = fmode[0]; vmode = EncodingUtils.vmode(vmodeAndVpermP); // clear shared vmodeVperm @@ -380,25 +377,25 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } } else { if (vmode.isNil()) { - ptr.flags |= OpenFile.WRITABLE; + this.flags = this.flags | OpenFile.WRITABLE; } } if (!string.isNil() && (ptr.flags & OpenFile.TRUNC) != 0) { ((RubyString) string).clear(); } if (string instanceof RubyString) { - ptr.string = (RubyString) string; + this.string = (RubyString) string; } if (argc == 1 && !string.isNil()) { - ptr.enc = ((RubyString) string).getEncoding(); + this.enc = ((RubyString) string).getEncoding(); } else { - ptr.enc = ioEncodable.enc; + this.enc = ioEncodable.enc; } - ptr.pos = 0; - ptr.lineno = 0; + this.pos = 0; + this.lineno = 0; if ((ptr.flags & OpenFile.SETENC_BY_BOM) != 0) set_encoding_by_bom(context); // funky way of shifting readwrite flags into object flags - flags |= (ptr.flags & OpenFile.READWRITE) * (STRIO_READABLE / OpenFile.READABLE); + strioFlags |= (ptr.flags & OpenFile.READWRITE) * (STRIO_READABLE / OpenFile.READABLE); } finally { if (locked) unlock(ptr); } @@ -412,17 +409,23 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (this == otherIO) return this; - ptr = otherIO.getPtr(); - flags = (byte) (flags & ~STRIO_READWRITE | otherIO.flags & STRIO_READWRITE); + otherIO.checkFrozen(); + this.string = otherIO.string; + this.enc = otherIO.enc; + this.pos = otherIO.pos; + this.lineno = otherIO.lineno; + this.flags = otherIO.flags; + this.ptr = this; + strioFlags = (byte) (strioFlags & ~STRIO_READWRITE | otherIO.strioFlags & STRIO_READWRITE); return this; } @JRubyMethod public IRubyObject binmode(ThreadContext context) { - StringIOData ptr = this.getPtr(); - ptr.enc = EncodingUtils.ascii8bitEncoding(context.runtime); - if (writable()) ptr.string.setEncoding(ptr.enc); + checkFrozen(); + this.enc = EncodingUtils.ascii8bitEncoding(context.runtime); + if (writable()) this.string.setEncoding(ptr.enc); return this; } @@ -464,7 +467,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if ( closed() ) return context.nil; // NOTE: This is 2.0 behavior to allow dup'ed StringIO to remain open when original is closed - flags &= ~STRIO_READWRITE; + strioFlags &= ~STRIO_READWRITE; return context.nil; } @@ -479,12 +482,13 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { public IRubyObject close_read(ThreadContext context) { // ~ checkReadable() : checkInitialized(); - if ( (getPtr().flags & OpenFile.READABLE) == 0 ) { + checkFrozen(); + if ( (ptr.flags & OpenFile.READABLE) == 0 ) { throw context.runtime.newIOError("not opened for reading"); } - int flags = this.flags; + int strioFlags = this.strioFlags; if ( ( flags & STRIO_READABLE ) != 0 ) { - this.flags = (byte) (flags & ~STRIO_READABLE); + this.strioFlags = (byte) (strioFlags & ~STRIO_READABLE); } return context.nil; } @@ -499,12 +503,13 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { public IRubyObject close_write(ThreadContext context) { // ~ checkWritable() : checkInitialized(); - if ( (getPtr().flags & OpenFile.WRITABLE) == 0 ) { + checkFrozen(); + if ( (ptr.flags & OpenFile.WRITABLE) == 0 ) { throw context.runtime.newIOError("not opened for writing"); } - int flags = this.flags; + int strioFlags = this.strioFlags; if ( ( flags & STRIO_WRITABLE ) != 0 ) { - this.flags = (byte) (flags & ~STRIO_WRITABLE); + this.strioFlags = (byte) (strioFlags & ~STRIO_WRITABLE); } return context.nil; } @@ -616,11 +621,11 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (!block.isGiven()) return enumeratorize(runtime, this, "each_byte"); checkReadable(); - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - ByteList bytes = ptr.string.getByteList(); + ByteList bytes = this.string.getByteList(); // Check the length every iteration, since // the block can modify this string. @@ -650,7 +655,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(name = {"eof", "eof?"}) public IRubyObject eof(ThreadContext context) { checkReadable(); - StringIOData ptr = getPtr(); + checkFrozen(); if (!isEndOfString()) return context.fals; return context.tru; } @@ -660,8 +665,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } private boolean isOutside(int pos) { - StringIOData ptr = getPtr(); - return ptr.string == null || pos >= ptr.string.size(); + checkFrozen(); + return this.string == null || pos >= this.string.size(); } @JRubyMethod(name = "getc") @@ -670,15 +675,15 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (isEndOfString()) return context.nil; - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - int start = ptr.pos; - RubyString string = ptr.string; + int start = this.pos; + RubyString string = this.string; int total = 1 + StringSupport.bytesToFixBrokenTrailingCharacter(string.getByteList(), start + 1); - ptr.pos += total; + this.pos = this.pos + total; return context.runtime.newString(string.getByteList().makeShared(start, total)); } finally { @@ -693,10 +698,10 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (isEndOfString()) return context.nil; int c; - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - c = ptr.string.getByteList().get(ptr.pos++) & 0xFF; + c = this.string.getByteList().get(ptr.pos++) & 0xFF; } finally { if (locked) unlock(ptr); } @@ -707,9 +712,9 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { // MRI: strio_substr // must be called under lock private RubyString strioSubstr(Ruby runtime, int pos, int len, Encoding enc) { - StringIOData ptr = this.getPtr(); + checkFrozen(); - final RubyString string = ptr.string; + final RubyString string = this.string; int rlen = string.size() - pos; if (len > rlen) len = rlen; @@ -758,25 +763,29 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(name = "gets", writes = FrameField.LASTLINE) public IRubyObject gets(ThreadContext context) { - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; return Getline.getlineCall(context, GETLINE, this, getEncoding()); } @JRubyMethod(name = "gets", writes = FrameField.LASTLINE) public IRubyObject gets(ThreadContext context, IRubyObject arg0) { - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0); } @JRubyMethod(name = "gets", writes = FrameField.LASTLINE) public IRubyObject gets(ThreadContext context, IRubyObject arg0, IRubyObject arg1) { - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0, arg1); } @JRubyMethod(name = "gets", writes = FrameField.LASTLINE) public IRubyObject gets(ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) { - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0, arg1, arg2); } @@ -800,7 +809,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { self.checkReadable(); if (limit == 0) { - if (self.getPtr().string == null) return context.nil; + self.checkFrozen(); + if (self.ptr.string == null) return context.nil; return RubyString.newEmptyString(context.runtime, self.getEncoding()); } @@ -816,8 +826,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { private static final Getline.Callback GETLINE_YIELD = (context, self, rs, limit, chomp, block) -> { IRubyObject line; - StringIOData ptr = self.getPtr(); - if (ptr.string == null || ptr.pos > ptr.string.size()) { + self.checkFrozen(); + if (self.string == null || self.pos > self.string.size()) { return self; } @@ -839,8 +849,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { RubyArray ary = (RubyArray) context.runtime.newArray(); IRubyObject line; - StringIOData ptr = self.getPtr(); - if (ptr.string == null || ptr.pos > ptr.string.size()) { + self.checkFrozen(); + if (self.string == null || self.pos > self.string.size()) { return null; } @@ -871,15 +881,15 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { return context.nil; } - StringIOData ptr = this.getPtr(); + checkFrozen(); Encoding enc = getEncoding(); boolean locked = lock(context, ptr); try { - final ByteList string = ptr.string.getByteList(); + final ByteList string = this.string.getByteList(); final byte[] stringBytes = string.getUnsafeBytes(); int begin = string.getBegin(); - int pos = ptr.pos; + int pos = this.pos; int s = begin + pos; int e = begin + string.getRealSize(); int p; @@ -955,8 +965,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } str = strioSubstr(runtime, pos, e - s - w, enc); } - ptr.pos = e - begin; - ptr.lineno++; + this.pos = e - begin; + this.lineno = this.lineno + 1; } finally { if (locked) unlock(ptr); } @@ -975,19 +985,24 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(name = {"length", "size"}) public IRubyObject length(ThreadContext context) { checkInitialized(); - RubyString myString = getPtr().string; + checkFrozen(); + RubyString myString = this.string; if (myString == null) return RubyFixnum.zero(context.runtime); return getRuntime().newFixnum(myString.size()); } @JRubyMethod(name = "lineno") public IRubyObject lineno(ThreadContext context) { - return context.runtime.newFixnum(getPtr().lineno); + checkFrozen(); + return context.runtime.newFixnum(ptr.lineno); } @JRubyMethod(name = "lineno=", required = 1) public IRubyObject set_lineno(ThreadContext context, IRubyObject arg) { - getPtr().lineno = RubyNumeric.fix2int(arg); + checkFrozen(); + StringIO stringIO = ptr; + int lineno1 = RubyNumeric.fix2int(arg); + stringIO.lineno = lineno1; return context.nil; } @@ -996,7 +1011,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { public IRubyObject pos(ThreadContext context) { checkInitialized(); - return context.runtime.newFixnum(getPtr().pos); + checkFrozen(); + return context.runtime.newFixnum(ptr.pos); } @JRubyMethod(name = "pos=", required = 1) @@ -1009,17 +1025,19 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (p > Integer.MAX_VALUE) throw getRuntime().newArgumentError("JRuby does not support StringIO larger than " + Integer.MAX_VALUE + " bytes"); - getPtr().pos = (int)p; + checkFrozen(); + StringIO stringIO = ptr; + stringIO.pos = (int)p; return arg; } private void strioExtend(ThreadContext context, int pos, int len) { - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - RubyString string = ptr.string; + RubyString string = this.string; final int olen = string.size(); long newSize = (long) pos + len; if (newSize > Integer.MAX_VALUE) { @@ -1054,12 +1072,14 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { checkModifiable(); if (ch instanceof RubyString) { - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; str = substrString((RubyString) ch, str, runtime); } else { byte c = RubyNumeric.num2chr(ch); - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; str = RubyString.newString(runtime, new byte[]{c}); } write(context, str); @@ -1091,8 +1111,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { IRubyObject str = context.nil; boolean binary = false; - StringIOData ptr = this.getPtr(); - int pos = ptr.pos; + checkFrozen(); + int pos = this.pos; boolean locked = lock(context, ptr); try { @@ -1120,11 +1140,11 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { break; } case 0: - RubyString myString = ptr.string; + RubyString myString = this.string; if (myString == null) { return context.nil; } - len = ptr.string.size(); + len = this.string.size(); if (len <= pos) { Encoding enc = binary ? ASCIIEncoding.INSTANCE : getEncoding(); if (str.isNil()) { @@ -1147,7 +1167,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { string = strioSubstr(runtime, pos, len, enc); } else { string = (RubyString) str; - RubyString myString = ptr.string; + RubyString myString = this.string; int rest = myString.size() - pos; if (len > rest) len = rest; string.resize(len); @@ -1161,7 +1181,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } } - ptr.pos += string.size(); + int pos1 = this.pos + string.size(); + this.pos = pos1; return string; } finally { @@ -1187,7 +1208,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @SuppressWarnings("fallthrough") private RubyString preadCommon(ThreadContext context, int argc, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) { IRubyObject str = context.nil; - StringIOData ptr = this.getPtr(); + checkFrozen(); Ruby runtime = context.runtime; int offset; final RubyString string; @@ -1238,7 +1259,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } string = (RubyString) str; - RubyString myString = ptr.string; + RubyString myString = this.string; int rest = myString.size() - offset; if (len > rest) len = rest; string.resize(len); @@ -1337,12 +1358,12 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { public IRubyObject rewind(ThreadContext context) { checkInitialized(); - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - ptr.pos = 0; - ptr.lineno = 0; + this.pos = 0; + this.lineno = 0; } finally { if (locked) unlock(ptr); } @@ -1370,7 +1391,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { whence = arg1; } - StringIOData ptr = this.getPtr(); + checkFrozen(); checkOpen(); @@ -1380,13 +1401,13 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { case 0: break; case 1: - offset += ptr.pos; + offset += this.pos; break; case 2: if (ptr.string == null) { offset += 0; } else { - offset += ptr.string.size(); + offset += this.string.size(); } break; default: @@ -1395,7 +1416,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (offset < 0) throw runtime.newErrnoEINVALError("invalid seek value"); - ptr.pos = offset; + this.pos = offset; } finally { if (locked) unlock(ptr); } @@ -1406,16 +1427,18 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(name = "string=", required = 1) public IRubyObject set_string(ThreadContext context, IRubyObject arg) { checkFrozen(); - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - ptr.flags &= ~OpenFile.READWRITE; + int flags2 = this.flags & ~OpenFile.READWRITE; + this.flags = flags2; RubyString str = arg.convertToString(); - ptr.flags = str.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE; - ptr.pos = 0; - ptr.lineno = 0; - return ptr.string = str; + int flags1 = str.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE; + this.flags = flags1; + this.pos = 0; + this.lineno = 0; + return this.string = str; } finally { if (locked) unlock(ptr); } @@ -1423,7 +1446,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod(name = "string") public IRubyObject string(ThreadContext context) { - RubyString string = getPtr().string; + checkFrozen(); + RubyString string = this.string; if (string == null) return context.nil; return string; @@ -1440,8 +1464,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { checkWritable(); int l = RubyFixnum.fix2int(len); - StringIOData ptr = this.getPtr(); - RubyString string = ptr.string; + checkFrozen(); + RubyString string = this.string; boolean locked = lock(context, ptr); try { @@ -1472,7 +1496,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { checkModifiable(); checkReadable(); - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; if (arg.isNil()) return arg; if (arg instanceof RubyInteger) { @@ -1499,13 +1524,13 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } private void ungetbyteCommon(ThreadContext context, int c) { - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - RubyString string = ptr.string; + RubyString string = this.string; string.modify(); - ptr.pos--; + this.pos = this.pos - 1; ByteList bytes = string.getByteList(); @@ -1513,7 +1538,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (ptr.pos == -1) { bytes.prepend((byte) c); - ptr.pos = 0; + this.pos = 0; } else { bytes.set(ptr.pos, c); } @@ -1530,12 +1555,12 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { private void ungetbyteCommon(ThreadContext context, byte[] ungetBytes, int cp, int cl) { if (cl == 0) return; - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - int pos = ptr.pos, len, rest; - RubyString str = ptr.string; + int pos = this.pos, len, rest; + RubyString str = this.string; ByteList strBytelist; byte[] strBytes; int s; @@ -1571,7 +1596,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } else { System.arraycopy(strBytes, s, strBytes, s + pos, cl); } - ptr.pos = pos; + this.pos = pos; } finally { if (locked) unlock(ptr); } @@ -1585,7 +1610,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { if (arg.isNil()) return arg; checkModifiable(); - if (getPtr().string == null) return context.nil; + checkFrozen(); + if (ptr.string == null) return context.nil; if (arg instanceof RubyInteger) { ungetbyteCommon(context, ((RubyInteger) ((RubyInteger) arg).op_mod(context, 256)).getIntValue()); @@ -1699,7 +1725,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { RubyString str = arg.asString(); int len, olen; - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { @@ -1718,12 +1744,12 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { len = str.size(); if (len == 0) return 0; checkModifiable(); - RubyString myString = ptr.string; + RubyString myString = this.string; olen = myString.size(); if ((ptr.flags & OpenFile.APPEND) != 0) { - ptr.pos = olen; + this.pos = olen; } - int pos = ptr.pos; + int pos = this.pos; if (pos == olen) { if (enc == EncodingUtils.ascii8bitEncoding(runtime) || encStr == EncodingUtils.ascii8bitEncoding(runtime)) { EncodingUtils.encStrBufCat(runtime, myString, strByteList, enc); @@ -1736,7 +1762,7 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { ByteList ptrByteList = myString.getByteList(); System.arraycopy(strByteList.getUnsafeBytes(), strByteList.getBegin(), ptrByteList.getUnsafeBytes(), ptrByteList.begin() + pos, len); } - ptr.pos = pos + len; + this.pos = pos + len; } finally { if (locked) unlock(ptr); } @@ -1810,14 +1836,14 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } } - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { - ptr.enc = enc; + this.enc = enc; // in read-only mode, StringIO#set_encoding no longer sets the encoding - RubyString string = ptr.string; + RubyString string = this.string; if (string != null && writable() && string.getEncoding() != enc) { string.modify(); string.setEncoding(enc); @@ -1846,22 +1872,22 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { @JRubyMethod public IRubyObject set_encoding_by_bom(ThreadContext context) { - StringIOData ptr = getPtr(); + checkFrozen(); if (setEncodingByBOM(context, ptr) == null) return context.nil; return context.runtime.getEncodingService().convertEncodingToRubyEncoding(ptr.enc); } - private Encoding setEncodingByBOM(ThreadContext context, StringIOData ptr) { - Encoding enc = detectBOM(context, ptr.string, (ctx, enc2, bomlen) -> { - ptr.pos = bomlen; + private Encoding setEncodingByBOM(ThreadContext context, StringIO ptr) { + Encoding enc = detectBOM(context, this.string, (ctx, enc2, bomlen) -> { + this.pos = bomlen; if (writable()) { - ptr.string.setEncoding(enc2); + this.string.setEncoding(enc2); } return enc2; }); - ptr.enc = enc; + this.enc = enc; return enc; } @@ -1929,12 +1955,12 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { checkReadable(); - StringIOData ptr = this.getPtr(); + checkFrozen(); boolean locked = lock(context, ptr); try { final Encoding enc = getEncoding(); - RubyString myString = ptr.string; + RubyString myString = this.string; final ByteList string = myString.getByteList(); final byte[] stringBytes = string.getUnsafeBytes(); int begin = string.getBegin(); @@ -1942,12 +1968,12 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { // check readability for each loop, since it could get closed checkReadable(); - int pos = ptr.pos; + int pos = this.pos; if (pos >= string.realSize()) return this; int c = StringSupport.codePoint(runtime, enc, stringBytes, begin + pos, stringBytes.length); int n = StringSupport.codeLength(enc, c); - ptr.pos = pos + n; + this.pos = pos + n; block.yield(context, runtime.newFixnum(c)); } } finally { @@ -2178,18 +2204,21 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } private boolean readable() { - return (flags & STRIO_READABLE) != 0 - && (getPtr().flags & OpenFile.READABLE) != 0; + if ((strioFlags & STRIO_READABLE) == 0) return false; + checkFrozen(); + return (ptr.flags & OpenFile.READABLE) != 0; } private boolean writable() { - return (flags & STRIO_WRITABLE) != 0 - && (getPtr().flags & OpenFile.WRITABLE) != 0; + if ((strioFlags & STRIO_WRITABLE) == 0) return false; + checkFrozen(); + return (ptr.flags & OpenFile.WRITABLE) != 0; } private boolean closed() { - return !((flags & STRIO_READWRITE) != 0 - && (getPtr().flags & OpenFile.READWRITE) != 0); + checkFrozen(); + return !((strioFlags & STRIO_READWRITE) != 0 + && (ptr.flags & OpenFile.READWRITE) != 0); } /* rb: readable */ @@ -2211,7 +2240,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } private void checkModifiable() { - final RubyString string = getPtr().string; + checkFrozen(); + final RubyString string = this.string; if (string == null) { /* Null device StringIO */ } else if (string.isFrozen()) { @@ -2222,7 +2252,8 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } private void checkInitialized() { - if (getPtr() == null) { + checkFrozen(); + if (ptr == null) { throw getRuntime().newIOError("uninitialized stream"); } } @@ -2233,13 +2264,14 @@ public class StringIO extends RubyObject implements EncodingCapable, DataType { } } - private static boolean lock(ThreadContext context, StringIOData ptr) { + private static boolean lock(ThreadContext context, StringIO ptr) { if (ptr.owner == context) return false; while (!LOCKED_UPDATER.compareAndSet(ptr, null, context)); // lock return true; } - private static void unlock(StringIOData ptr) { + private static void unlock(StringIO ptr) { ptr.owner = null; // unlock } + }