Skip to content
Browse files

Eliminate most transient strings in compiled D*Nodes.

* Static portions are cached bytelist, direct append.
* EvStr with Fixnum/Float/Symbol body append object directly.
* Remaining cases coerce to String as before.
  • Loading branch information...
1 parent 71fa23b commit 0ec62706b9851861cdb86120ed6f00428b88df42 @headius headius committed with Prathamesh Sonpatki Sep 17, 2012
View
7 src/org/jruby/ast/DNode.java
@@ -6,6 +6,7 @@
import org.jruby.RubyFloat;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
+import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
@@ -71,11 +72,7 @@ public void appendToString(Ruby runtime, ThreadContext context, IRubyObject self
if (bodyNode == null) return;
IRubyObject body = bodyNode.interpret(runtime, context, self, aBlock);
- if (body instanceof RubyFixnum || body instanceof RubyFloat || body instanceof RubySymbol) {
- string.append19(body);
- } else {
- string.append19(body.asString());
- }
+ RuntimeHelpers.shortcutAppend(string, body);
} else if (is19()) {
string.append19(node.interpret(runtime, context, self, aBlock));
} else {
View
18 src/org/jruby/compiler/ASTCompiler.java
@@ -2250,10 +2250,22 @@ public void compileDStr(Node node, BodyCompiler context, boolean expr) {
final DStrNode dstrNode = (DStrNode) node;
ArrayCallback dstrCallback = new ArrayCallback() {
-
public void nextValue(BodyCompiler context, Object sourceArray,
int index) {
- compile(dstrNode.get(index), context, true);
+ Node nextNode = dstrNode.get(index);
+
+ switch (nextNode.getNodeType()) {
+ case STRNODE:
+ context.appendByteList(((StrNode)nextNode).getValue(), ((StrNode)nextNode).getCodeRange(), dstrNode.is19());
+ break;
+ case EVSTRNODE:
+ compile(((EvStrNode)nextNode).getBody(), context, true);
+ context.shortcutAppend();
+ break;
+ default:
+ compile(nextNode, context, true);
+ context.appendObject(dstrNode.is19());
+ }
}
};
@@ -2263,7 +2275,7 @@ public void nextValue(BodyCompiler context, Object sourceArray,
enc = dstrNode.getEncoding();
}
- context.createNewString(dstrCallback, dstrNode.size(), enc);
+ context.buildNewString(dstrCallback, dstrNode.size(), enc);
} else {
// not an expression, only compile the elements
for (Node nextNode : dstrNode.childNodes()) {
View
22 src/org/jruby/compiler/BodyCompiler.java
@@ -139,6 +139,28 @@
public void createNewSymbol(ArrayCallback callback, int count, Encoding encoding);
/**
+ * Build a string using the given callback. A String will be create at the start,
+ * and each iteration is expected to leave a String on the stack.
+ */
+ public void buildNewString(ArrayCallback callback, int count, Encoding encoding);
+
+ /**
+ * Append the given bytelist + coderange to the string currently on the stack.
+ */
+ public void appendByteList(ByteList value, int codeRange, boolean is19);
+
+ /**
+ * Append the object on stack to the string below it.
+ */
+ public void appendObject(boolean is19);
+
+ /**
+ * A "shortcut" append that skips conversions to String where possible.
+ * Same stack requirements as appendObject.
+ */
+ public void shortcutAppend();
+
+ /**
* Generate a new "Symbol" value (or fetch the existing one).
*/
public void createNewSymbol(String name);
View
43 src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -448,14 +448,47 @@ public void createNewString(ArrayCallback callback, int count, Encoding encoding
for (int i = 0; i < count; i++) {
callback.nextValue(this, null, i);
- if (encoding != null) {
- method.invokevirtual(p(RubyString.class), "append19", sig(RubyString.class, params(IRubyObject.class)));
- } else {
- method.invokevirtual(p(RubyString.class), "append", sig(RubyString.class, params(IRubyObject.class)));
- }
+ appendObject(encoding != null);
+ }
+ }
+
+ public void buildNewString(ArrayCallback callback, int count, Encoding encoding) {
+ loadRuntime();
+ method.ldc(StandardASMCompiler.STARTING_DSTR_FACTOR * count);
+ if (encoding == null) {
+ method.invokestatic(p(RubyString.class), "newStringLight", sig(RubyString.class, Ruby.class, int.class));
+ } else {
+ script.getCacheCompiler().cacheEncoding(this, encoding);
+ method.invokestatic(p(RubyString.class), "newStringLight", sig(RubyString.class, Ruby.class, int.class, Encoding.class));
+ }
+
+ for (int i = 0; i < count; i++) {
+ callback.nextValue(this, null, i);
+ }
+ }
+
+ public void appendByteList(ByteList value, int codeRange, boolean is19) {
+ script.getCacheCompiler().cacheByteList(this, value);
+ if (is19) {
+ method.ldc(codeRange);
+ invokeUtilityMethod("appendByteList19", sig(RubyString.class, RubyString.class, ByteList.class, int.class));
+ } else {
+ invokeUtilityMethod("appendByteList", sig(RubyString.class, RubyString.class, ByteList.class));
}
}
+ public void appendObject(boolean is19) {
+ if (is19) {
+ method.invokevirtual(p(RubyString.class), "append19", sig(RubyString.class, params(IRubyObject.class)));
+ } else {
+ method.invokevirtual(p(RubyString.class), "append", sig(RubyString.class, params(IRubyObject.class)));
+ }
+ }
+
+ public void shortcutAppend() {
+ invokeUtilityMethod("shortcutAppend", sig(RubyString.class, RubyString.class, IRubyObject.class));
+ }
+
public void createNewSymbol(ArrayCallback callback, int count, Encoding encoding) {
loadRuntime();
createNewString(callback, count, encoding);
View
38 src/org/jruby/javasupport/util/RuntimeHelpers.java
@@ -1,24 +1,6 @@
package org.jruby.javasupport.util;
-import org.jruby.MetaClass;
-import org.jruby.NativeException;
-import org.jruby.Ruby;
-import org.jruby.RubyArray;
-import org.jruby.RubyBasicObject;
-import org.jruby.RubyBoolean;
-import org.jruby.RubyClass;
-import org.jruby.RubyException;
-import org.jruby.RubyFixnum;
-import org.jruby.RubyHash;
-import org.jruby.RubyInstanceConfig;
-import org.jruby.RubyKernel;
-import org.jruby.RubyLocalJumpError;
-import org.jruby.RubyMatchData;
-import org.jruby.RubyModule;
-import org.jruby.RubyProc;
-import org.jruby.RubyRegexp;
-import org.jruby.RubyString;
-import org.jruby.RubySymbol;
+import org.jruby.*;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.DAsgnNode;
@@ -2760,4 +2742,22 @@ public static RubyClass newClassForIR(ThreadContext context, String name, IRubyO
return classContainer.defineOrGetClassUnder(name, sc);
}
+
+ public static RubyString appendByteList(RubyString target, ByteList source) {
+ target.getByteList().append(source);
+ return target;
+ }
+
+ public static RubyString appendByteList19(RubyString target, ByteList source, int codeRange) {
+ target.cat19(source, codeRange);
+ return target;
+ }
+
+ public static RubyString shortcutAppend(RubyString string, IRubyObject object) {
+ if (object instanceof RubyFixnum || object instanceof RubyFloat || object instanceof RubySymbol) {
+ return string.append19(object);
+ } else {
+ return string.append19(object.asString());
+ }
+ }
}

0 comments on commit 0ec6270

Please sign in to comment.
Something went wrong with that request. Please try again.