Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Truffle ropes #3605

Closed
wants to merge 144 commits into from
Closed

Truffle ropes #3605

wants to merge 144 commits into from

Conversation

nirvdrum
Copy link
Contributor

This is the initial work in changing the storage strategy for Strings in JRuby+Truffle from ByteList to Rope. There was a fair bit of rote translation work here. I haven't spend any appreciable amount of time on optimizing anything yet. And Symbols are still backed by ByteList.

I tried to make the code work well for both JRuby backends. For simplicity I did pull in some Truffle annotations, but it should be easy to divorce the two.

@chrisseaton @pitr-ch @eregon Please review at your leisure.

@enebo @headius @lopex This work may be of interest to you.

@nirvdrum
Copy link
Contributor Author

I should note that all feedback is appreciated. But please be open to the answer "I didn't get to that yet."

tagged_example "'abc' == 'abc'", true # seems to fail sometimes
example "x = 'abc'; x == x", true
example "x = 'abc'; x == x.dup", true
Copy link
Contributor

Choose a reason for hiding this comment

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

This is where the optimisation magic starts! This dup has been completely eliminated by the PE.

Copy link
Member

Choose a reason for hiding this comment

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

How does it work? The rope is only shallow-copied? Then ropes are purely immutable?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, so dup allocates a tiny new wrapper around the same rope node and then the == is just a reference comparison in the fast path, which of course all PEs really well.

@chrisseaton
Copy link
Contributor

Looks good to merge to me.

for (Object string : strings) {
assert RubyGuards.isRubyString(string);

if (builder == null) {
builder = dupNode.call(frame, string, "dup", null);
} else {
builder = concatNode.call(frame, builder, "concat", null, string);
builder = appendNode.call(frame, builder, "append", null, string);
Copy link
Member

Choose a reason for hiding this comment

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

What is append?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A Rubinius method/primitive. It does much of the same without some of the extra checking that concat needs to perform.

Copy link
Member

Choose a reason for hiding this comment

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

But this means it's a public Ruby method. If it's not needed as such, it could be just a normal node.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rubinius calls this method. We had it shimmed previously (

class String
def append(other)
self << other
end
end
). I just implemented it as a primitive as Rubinius does. The new method lives in bootstrap/string.rb. This was necessary because I moved a lot of String#concat out to Rubinus, which uses String#append to implement the method. Our old shim would have been cyclical.

I could indeed just call the method rather than go through the full dispatch here. I've been avoiding that generally in case we need to run through taint or frozen checks.

Copy link
Member

Choose a reason for hiding this comment

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

I would go for the having an AppendNode and using executeStringAppend here, it's much lighter weight.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to defer this until after the merge. It's no worse off than what we had before and this PR is already getting rather long.

int getCodeRange(DynamicObject object);
void setCodeRange(DynamicObject object, int codeRange);
Rope getRope(DynamicObject object);
void setRope(DynamicObject object, Rope byteList);
Copy link
Member

Choose a reason for hiding this comment

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

Rope rope here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll grep for similar issues.

}
}

@CompilerDirectives.TruffleBoundary
Copy link
Member

Choose a reason for hiding this comment

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

Didn't we make a convention to use just @TruffleBoundary ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably. I'll fix them. It's just how IntelliJ autocompletes.

@pitr-ch
Copy link
Member

pitr-ch commented Jan 20, 2016

👍 nice work

Doing a critical operation like this purely in Ruby caused performance regressions that we need to investigate.
…ead of CR_7BIT.

While there shouldn't be a difference, it can lead Strings down wrong optimization paths. For now we'll match what MRI and JRuby do to make things simpler.
This should help cases where a byte buffer is pre-allocated using String#* (such as with StringIO). Also, rope links probably cost more than just making a flat array in this case.
@chrisseaton chrisseaton added this to the truffle-dev milestone Jan 27, 2016
@nirvdrum nirvdrum closed this Jan 27, 2016
@nirvdrum nirvdrum mentioned this pull request Jan 27, 2016
@enebo enebo added this to the Non-Release milestone Dec 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants