Skip to content

Commit

Permalink
Better fix for FrozenString. String-fed FrozenStrings should just pas…
Browse files Browse the repository at this point in the history
…s through to String Literal

rather than get reconstructed from generate bytelist.
Frozen string optimization did not propagate coderange to FrozenString.
XStrNode when constructed from StrNode did not propagate coderange.
enebo committed Mar 12, 2015
1 parent f7622b2 commit 18d9c88
Showing 6 changed files with 43 additions and 26 deletions.
8 changes: 7 additions & 1 deletion core/src/main/java/org/jruby/ast/XStrNode.java
Original file line number Diff line number Diff line change
@@ -42,11 +42,13 @@
*/
public class XStrNode extends Node implements ILiteralNode {
private final ByteList value;
private int coderange;

public XStrNode(ISourcePosition position, ByteList value) {
public XStrNode(ISourcePosition position, ByteList value, int coderange) {
// FIXME: Shouldn't this have codeRange like StrNode?
super(position, false);
this.value = (value == null ? ByteList.create("") : value);
this.coderange = coderange;
}

public NodeType getNodeType() {
@@ -68,6 +70,10 @@ public <T> T accept(NodeVisitor<T> iVisitor) {
public ByteList getValue() {
return value;
}

public int getCodeRange() {
return coderange;
}

public List<Node> childNodes() {
return EMPTY_LIST;
8 changes: 4 additions & 4 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1004,10 +1004,10 @@ public Operand buildCall(CallNode callNode) {
Node callArgsNode = callNode.getArgsNode();
Node receiverNode = callNode.getReceiverNode();

// check for "string".freeze
// Frozen string optimization: check for "string".freeze
if (receiverNode instanceof StrNode && callNode.getName().equals("freeze")) {
// frozen string optimization
return new FrozenString(((StrNode)receiverNode).getValue(), StringSupport.CR_7BIT);
StrNode asString = (StrNode) receiverNode;
return new FrozenString(asString.getValue(), asString.getCodeRange());
}

// Though you might be tempted to move this build into the CallInstr as:
@@ -3399,7 +3399,7 @@ public Operand buildWhile(final WhileNode whileNode) {
}

public Operand buildXStr(XStrNode node) {
return addResultInstr(new BacktickInstr(createTemporaryVariable(), new Operand[] { new StringLiteral(node.getValue())}));
return addResultInstr(new BacktickInstr(createTemporaryVariable(), new Operand[] { new StringLiteral(node.getValue(), node.getCodeRange())}));
}

public Operand buildYield(YieldNode node) {
9 changes: 7 additions & 2 deletions core/src/main/java/org/jruby/ir/operands/FrozenString.java
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.StringSupport;

/**
* Represents a literal string value.
@@ -18,12 +17,18 @@
* This is not like a Java string.
*/
public class FrozenString extends StringLiteral {
/**
* Used by persistence and by .freeze optimization
*/
public FrozenString(ByteList byteList, int cr) {
super(OperandType.FROZEN_STRING, byteList, cr);
}

/**
* IRBuild.buildGetDefinition returns a frozen string and this is for all intern'd Java strings.
*/
public FrozenString(String s) {
this(ByteList.create(s), StringSupport.CR_7BIT);
super(s);
}

@Override
24 changes: 14 additions & 10 deletions core/src/main/java/org/jruby/ir/operands/StringLiteral.java
Original file line number Diff line number Diff line change
@@ -32,27 +32,31 @@ public class StringLiteral extends Operand {
final public String string;
final public int coderange;

public StringLiteral(ByteList val) {
this(OperandType.STRING_LITERAL, val, StringSupport.CR_7BIT);
}

public StringLiteral(ByteList val, int coderange) {
this(OperandType.STRING_LITERAL, val, coderange);
}

protected StringLiteral(OperandType type, ByteList val, int coderange) {
this(type, internedStringFromByteList(val), val, coderange);

}

protected StringLiteral(OperandType type, String string, ByteList bytelist, int coderange) {
super(type);

bytelist = val;
this.bytelist = bytelist;
this.coderange = coderange;
String stringTemp;
this.string = string;
}

// If Encoding has an instance of a Charset can it ever raise unsupportedcharsetexception? because this
// helper called copes with charset == null...
private static String internedStringFromByteList(ByteList val) {
try {
stringTemp = Helpers.byteListToString(bytelist);
return Helpers.byteListToString(val).intern();
} catch (UnsupportedCharsetException e) {
stringTemp = bytelist.toString();
return val.toString().intern();
}
// FIXME:
string = stringTemp.intern();
}

public StringLiteral(String s) {
13 changes: 7 additions & 6 deletions core/src/main/java/org/jruby/parser/RubyParser.java
Original file line number Diff line number Diff line change
@@ -128,7 +128,8 @@
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;
import org.jruby.util.cli.Options;

import org.jruby.util.StringSupport;

public class RubyParser {
protected ParserSupport support;
protected RubyLexer lexer;
@@ -148,7 +149,7 @@ public void setWarnings(IRubyWarnings warnings) {
support.setWarnings(warnings);
lexer.setWarnings(warnings);
}
// line 152 "-"
// line 153 "-"
// %token constants
public static final int kCLASS = 257;
public static final int kMODULE = 258;
@@ -4277,9 +4278,9 @@ public Object yyparse (RubyLexer yyLex) throws java.io.IOException {
ISourcePosition position = support.getPosition(((Node)yyVals[-1+yyTop]));

if (((Node)yyVals[-1+yyTop]) == null) {
yyVal = new XStrNode(position, null);
yyVal = new XStrNode(position, null, StringSupport.CR_7BIT);
} else if (((Node)yyVals[-1+yyTop]) instanceof StrNode) {
yyVal = new XStrNode(position, (ByteList) ((StrNode)yyVals[-1+yyTop]).getValue().clone());
yyVal = new XStrNode(position, (ByteList) ((StrNode)yyVals[-1+yyTop]).getValue().clone(), ((StrNode)yyVals[-1+yyTop]).getCodeRange());
} else if (((Node)yyVals[-1+yyTop]) instanceof DStrNode) {
yyVal = new DXStrNode(position, ((DStrNode)yyVals[-1+yyTop]));

@@ -5245,7 +5246,7 @@ public Object yyparse (RubyLexer yyLex) throws java.io.IOException {
}
};
}
// line 2510 "RubyParser.y"
// line 2511 "RubyParser.y"

/** The parse method use an lexer stream and parse it to an AST node
* structure
@@ -5264,4 +5265,4 @@ public RubyParserResult parse(ParserConfiguration configuration, LexerSource sou
return support.getResult();
}
}
// line 9793 "-"
// line 9794 "-"
7 changes: 4 additions & 3 deletions core/src/main/java/org/jruby/parser/RubyParser.y
Original file line number Diff line number Diff line change
@@ -125,7 +125,8 @@ import org.jruby.lexer.yacc.SyntaxException.PID;
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;
import org.jruby.util.cli.Options;

import org.jruby.util.StringSupport;

public class RubyParser {
protected ParserSupport support;
protected RubyLexer lexer;
@@ -1885,9 +1886,9 @@ xstring : tXSTRING_BEG xstring_contents tSTRING_END {
ISourcePosition position = support.getPosition($2);

if ($2 == null) {
$$ = new XStrNode(position, null);
$$ = new XStrNode(position, null, StringSupport.CR_7BIT);
} else if ($2 instanceof StrNode) {
$$ = new XStrNode(position, (ByteList) $<StrNode>2.getValue().clone());
$$ = new XStrNode(position, (ByteList) $<StrNode>2.getValue().clone(), $<StrNode>2.getCodeRange());
} else if ($2 instanceof DStrNode) {
$$ = new DXStrNode(position, $<DStrNode>2);

1 comment on commit 18d9c88

@scrhartley
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you now remove that FIXME in XStrNode?
"// FIXME: Shouldn't this have codeRange like StrNode?"

Please sign in to comment.