Skip to content

Instantly share code, notes, and snippets.

@headius
Last active September 1, 2016 19:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/59e19a3a4a45c63b06cc9876a8148e28 to your computer and use it in GitHub Desktop.
Save headius/59e19a3a4a45c63b06cc9876a8148e28 to your computer and use it in GitHub Desktop.
Memory improvement for #inspect, from jruby/jruby#4127
diff --git a/core/src/main/java/org/jruby/RubyBasicObject.java b/core/src/main/java/org/jruby/RubyBasicObject.java
index fc181c9..107146a 100644
--- a/core/src/main/java/org/jruby/RubyBasicObject.java
+++ b/core/src/main/java/org/jruby/RubyBasicObject.java
@@ -69,6 +69,7 @@ import org.jruby.runtime.builtin.Variable;
import org.jruby.runtime.component.VariableEntry;
import org.jruby.runtime.marshal.CoreObjectType;
import org.jruby.util.ArraySupport;
+import org.jruby.util.ConvertBytes;
import org.jruby.util.IdUtil;
import org.jruby.util.TypeConverter;
import org.jruby.util.unsafe.UnsafeHolder;
@@ -78,6 +79,9 @@ import static org.jruby.runtime.invokedynamic.MethodNames.OP_EQUAL;
import static org.jruby.runtime.invokedynamic.MethodNames.OP_CMP;
import static org.jruby.runtime.invokedynamic.MethodNames.EQL;
import static org.jruby.runtime.invokedynamic.MethodNames.INSPECT;
+import static org.jruby.util.io.EncodingUtils.encStrBufCat;
+import static org.jruby.util.io.EncodingUtils.strBufCat;
+
import org.jruby.runtime.ivars.VariableTableManager;
/**
@@ -1096,21 +1100,30 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
return to_s();
}
+ private static final byte[] INSPECT_POUND_LT = "#<".getBytes();
+ private static final byte[] INSPECT_COLON_ZERO_X = ":0x".getBytes();
+ private static final byte[] INSPECT_SPACE_DOT_DOT_DOT_GT = " ...>".getBytes();
+ private static final byte[] INSPECT_COMMA = ",".getBytes();
+ private static final byte[] INSPECT_SPACE = " ".getBytes();
+ private static final byte[] INSPECT_EQUALS = "=".getBytes();
+ private static final byte[] INSPECT_GT = ">".getBytes();
+
public final IRubyObject hashyInspect() {
final Ruby runtime = getRuntime();
- String cname = getMetaClass().getRealClass().getName();
- StringBuilder part = new StringBuilder(2 + cname.length() + 3 + 8 + 1); // #<Object:0x5a1c0542>
- part.append("#<").append(cname).append(":0x");
- part.append(Integer.toHexString(inspectHashCode()));
+ RubyString name = (RubyString) getMetaClass().getRealClass().name();
+ RubyString part = RubyString.newStringLight(runtime, 2 + name.size() + 3 + 8 + 1); // #<Object:0x5a1c0542>
+ encStrBufCat(runtime, part, INSPECT_POUND_LT);
+ encStrBufCat(runtime, part, name.getByteList());
+ encStrBufCat(runtime, part, INSPECT_COLON_ZERO_X);
+ encStrBufCat(runtime, part, ConvertBytes.longToCharBytes(inspectHashCode()));
if (runtime.isInspecting(this)) {
- /* 6:tags 16:addr 1:eos */
- part.append(" ...>");
- return RubyString.newString(runtime, part);
+ encStrBufCat(runtime, part, INSPECT_SPACE_DOT_DOT_DOT_GT);
+ return part;
}
try {
runtime.registerInspecting(this);
- return RubyString.newString(runtime, inspectObj(runtime, part));
+ return inspectObj(runtime, part);
} finally {
runtime.unregisterInspecting(this);
}
@@ -1150,21 +1163,25 @@ public class RubyBasicObject implements Cloneable, IRubyObject, Serializable, Co
* The internal helper method that takes care of the part of the
* inspection that inspects instance variables.
*/
- private StringBuilder inspectObj(final Ruby runtime, StringBuilder part) {
+ private RubyString inspectObj(final Ruby runtime, RubyString part) {
final ThreadContext context = runtime.getCurrentContext();
- String sep = "";
+ boolean first = true;
for (Map.Entry<String, VariableAccessor> entry : metaClass.getVariableTableManager().getVariableAccessorsForRead().entrySet()) {
Object value = entry.getValue().get(this);
if (!(value instanceof IRubyObject) || !IdUtil.isInstanceVariable(entry.getKey())) continue;
IRubyObject obj = (IRubyObject) value;
- part.append(sep).append(' ').append(entry.getKey()).append('=');
- part.append(sites(context).inspect.call(context, obj, obj));
- sep = ",";
+ if (!first) encStrBufCat(runtime, part, INSPECT_COMMA);
+ encStrBufCat(runtime, part, INSPECT_SPACE);
+ encStrBufCat(runtime, part, entry.getKey().getBytes());
+ encStrBufCat(runtime, part, INSPECT_EQUALS);
+ encStrBufCat(runtime, part, sites(context).inspect.call(context, obj, obj).convertToString().getByteList());
+
+ first = false;
}
- part.append('>');
+ encStrBufCat(runtime, part, INSPECT_GT);
return part;
}
diff --git a/core/src/main/java/org/jruby/util/io/EncodingUtils.java b/core/src/main/java/org/jruby/util/io/EncodingUtils.java
index 9297b94..fa32383 100644
--- a/core/src/main/java/org/jruby/util/io/EncodingUtils.java
+++ b/core/src/main/java/org/jruby/util/io/EncodingUtils.java
@@ -1625,6 +1625,12 @@ public class EncodingUtils {
str.modify();
strBufCat(str.getByteList(), ptrBytes, ptr, len);
}
+ public static void strBufCat(ByteList str, ByteList ptr) {
+ strBufCat(str, ptr.getUnsafeBytes(), ptr.getBegin(), ptr.getRealSize());
+ }
+ public static void strBufCat(ByteList str, byte[] ptrBytes) {
+ strBufCat(str, ptrBytes, 0, ptrBytes.length);
+ }
public static void strBufCat(ByteList str, byte[] ptrBytes, int ptr, int len) {
int total, off = -1;
@@ -1647,6 +1653,13 @@ public class EncodingUtils {
encCrStrBufCat(runtime, str, ptr.getUnsafeBytes(), ptr.getBegin(), ptr.getRealSize(),
enc, StringSupport.CR_UNKNOWN, null);
}
+ public static void encStrBufCat(Ruby runtime, RubyString str, ByteList ptr) {
+ encCrStrBufCat(runtime, str, ptr.getUnsafeBytes(), ptr.getBegin(), ptr.getRealSize(),
+ ptr.getEncoding(), StringSupport.CR_UNKNOWN, null);
+ }
+ public static void encStrBufCat(Ruby runtime, RubyString str, byte[] ptrBytes) {
+ encCrStrBufCat(runtime, str, ptrBytes, 0, ptrBytes.length, USASCIIEncoding.INSTANCE, StringSupport.CR_UNKNOWN, null);
+ }
public static void encStrBufCat(Ruby runtime, RubyString str, byte[] ptrBytes, int ptr, int len, Encoding enc) {
encCrStrBufCat(runtime, str, ptrBytes, ptr, len,
enc, StringSupport.CR_UNKNOWN, null);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment