Skip to content

Commit

Permalink
Merge branch 'master' into truffle-head
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Jan 3, 2015
2 parents 63420d6 + 76a73e7 commit b4c11c6
Show file tree
Hide file tree
Showing 17 changed files with 525 additions and 293 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -98,3 +98,4 @@ core/.classpath
core/.gitignore
core/.project
core/.settings
core/.apt_generated
265 changes: 16 additions & 249 deletions core/src/main/java/org/jruby/RubyString.java

Large diffs are not rendered by default.

27 changes: 13 additions & 14 deletions core/src/main/java/org/jruby/truffle/nodes/control/AndNode.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
Expand All @@ -9,16 +9,14 @@
*/
package org.jruby.truffle.nodes.control;

import com.oracle.truffle.api.*;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.RubyContext;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;

/**
* Represents a Ruby {@code and} or {@code &&} expression.
Expand All @@ -28,6 +26,7 @@ public class AndNode extends RubyNode {
@Child protected RubyNode left;
@Child protected BooleanCastNode leftCast;
@Child protected RubyNode right;
private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile();

public AndNode(RubyContext context, SourceSection sourceSection, RubyNode left, RubyNode right) {
super(context, sourceSection);
Expand All @@ -39,12 +38,12 @@ public AndNode(RubyContext context, SourceSection sourceSection, RubyNode left,
@Override
public Object execute(VirtualFrame frame) {
final Object leftValue = left.execute(frame);

if (!leftCast.executeBoolean(frame, leftValue)) {
boolean leftBoolean = leftCast.executeBoolean(frame, leftValue);
if (conditionProfile.profile(leftBoolean)) {
// Right expression evaluated and returned if left expression returns true.
return right.execute(frame);
} else {
return leftValue;
}

return right.execute(frame);
}

}
39 changes: 37 additions & 2 deletions core/src/main/java/org/jruby/truffle/nodes/core/FileNodes.java
Expand Up @@ -17,6 +17,7 @@
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import jnr.posix.FileStat;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.core.RubyArray;
Expand Down Expand Up @@ -65,7 +66,7 @@ public RubyNilClass close(RubyFile file) {

}

@CoreMethod(names = "delete", onSingleton = true, required = 1)
@CoreMethod(names = { "delete", "unlink" }, onSingleton = true, required = 1)
public abstract static class DeleteNode extends CoreMethodNode {

public DeleteNode(RubyContext context, SourceSection sourceSection) {
Expand All @@ -87,7 +88,7 @@ public int delete(RubyString file) {

}

@CoreMethod(names = "directory?", onSingleton = true, optional = 1)
@CoreMethod(names = "directory?", onSingleton = true, required = 1)
public abstract static class DirectoryNode extends CoreMethodNode {

public DirectoryNode(RubyContext context, SourceSection sourceSection) {
Expand Down Expand Up @@ -442,6 +443,40 @@ public Object read(RubyString file) {

}

@CoreMethod(names = "symlink?", onSingleton = true, required = 1)
public abstract static class SymlinkQueryNode extends CoreMethodNode {

public SymlinkQueryNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SymlinkQueryNode(SymlinkQueryNode prev) {
super(prev);
}

@Specialization
public boolean symlinkQuery(RubyString fileName) {
notDesignedForCompilation();

try {
// Note: We can't use file.exists() to check whether the symlink
// exists or not, because that method returns false for existing
// but broken symlink. So, we try without the existence check,
// but in the try-catch block.
// MRI behavior: symlink? on broken symlink should return true.
FileStat stat = getContext().getRuntime().getPosix().allocateStat();

if (getContext().getRuntime().getPosix().lstat(fileName.toString(), stat) < 0) {
stat = null;
}

return (stat != null && stat.isSymlink());
} catch (SecurityException re) {
return false;
}
}
}

@CoreMethod(names = "write", required = 1)
public abstract static class WriteNode extends CoreMethodNode {

Expand Down
187 changes: 186 additions & 1 deletion core/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
Expand Up @@ -20,6 +20,7 @@
import org.joni.Matcher;
import org.joni.Option;
import org.joni.Region;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.runtime.Visibility;
Expand Down Expand Up @@ -738,6 +739,29 @@ public int getByte(RubyString string, int index) {
}
}

@CoreMethod(names = "include?", required = 1)
public abstract static class IncludeQueryNode extends CoreMethodNode {

public IncludeQueryNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public IncludeQueryNode(IncludeQueryNode prev) {
super(prev);
}

@Specialization
public boolean includeQuery(RubyString string, RubyString otherString) {
notDesignedForCompilation();

int foundIndex = StringSupport.index(string, string.getBytes(), string.length(),
otherString, otherString.getBytes(), otherString.length(),
0, string.getBytes().getEncoding());

return foundIndex != -1;
}
}

@CoreMethod(names = "inspect")
public abstract static class InspectNode extends CoreMethodNode {

Expand Down Expand Up @@ -809,6 +833,69 @@ public Object initializeCopy(RubyString self, RubyString from) {

}

@CoreMethod(names = "insert", required = 2, lowerFixnumParameters = 0)
public abstract static class InsertNode extends CoreMethodNode {

@Child protected ConcatNode concatNode;
@Child protected GetIndexNode getIndexNode;

public InsertNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
concatNode = StringNodesFactory.ConcatNodeFactory.create(context, sourceSection, new RubyNode[]{});
getIndexNode = StringNodesFactory.GetIndexNodeFactory.create(context, sourceSection, new RubyNode[]{});
}

public InsertNode(InsertNode prev) {
super(prev);
concatNode = prev.concatNode;
getIndexNode = prev.getIndexNode;
}

@Specialization
public RubyString insert(RubyString string, int index, RubyString otherString) {
notDesignedForCompilation();

if (string.isFrozen()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(getContext().getCoreLibrary().frozenError("String", this));
}

if (index == -1) {
concatNode.concat(string, otherString);

return string;

} else if (index < 0) {
// Incrementing first seems weird, but MRI does it and it's significant because it uses the modified
// index value in its error messages. This seems wrong, but we should be compatible.
index++;

if (-index > string.length()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(getContext().getCoreLibrary().indexError(String.format("index %d out of string", index), this));
}

index = index + string.length();

} else if (index > string.length()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(getContext().getCoreLibrary().indexError(String.format("index %d out of string", index), this));
}

RubyString firstPart = getIndexNode.getIndex(string, 0, index);
RubyString secondPart = getIndexNode.getIndex(string, index, string.length());

RubyString concatenated = concatNode.concat(concatNode.concat(firstPart, otherString), secondPart);

string.set(concatenated.getBytes());

return string;
}
}

@CoreMethod(names = "ljust", required = 1, optional = 1, lowerFixnumParameters = 0)
public abstract static class LjustNode extends CoreMethodNode {

Expand Down Expand Up @@ -879,6 +966,52 @@ public int ord(RubyString string) {
}
}

@CoreMethod(names = "rindex", required = 1, optional = 1, lowerFixnumParameters = 1)
public abstract static class RindexNode extends CoreMethodNode {

public RindexNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public RindexNode(RindexNode prev) {
super(prev);
}

@Specialization
public Object rindex(RubyString string, RubyString subString, @SuppressWarnings("unused") UndefinedPlaceholder endPosition) {
notDesignedForCompilation();

return rindex(string, subString, string.length());
}

@Specialization
public Object rindex(RubyString string, RubyString subString, int endPosition) {
notDesignedForCompilation();

int normalizedEndPosition = endPosition;

if (endPosition < 0) {
normalizedEndPosition = endPosition + string.length();

if (normalizedEndPosition < 0) {
return getContext().getCoreLibrary().getNilObject();
}
} else if (endPosition > string.length()) {
normalizedEndPosition = string.length();
}

int result = StringSupport.rindex(string.getBytes(), string.length(), subString.getBytes(), subString.length(),
normalizedEndPosition, subString, string.getBytes().getEncoding()
);

if (result >= 0) {
return result;
} else {
return getContext().getCoreLibrary().getNilObject();
}
}
}

@CoreMethod(names = "rjust", required = 1, optional = 1, lowerFixnumParameters = 0)
public abstract static class RjustNode extends CoreMethodNode {

Expand Down Expand Up @@ -1032,7 +1165,7 @@ public SizeNode(SizeNode prev) {

@Specialization
public int size(RubyString string) {
return string.getBytes().getRealSize();
return string.length();
}
}

Expand Down Expand Up @@ -1116,6 +1249,58 @@ public RubyString sub(RubyString string, RubyRegexp regexp, RubyString replaceme
}
}

@CoreMethod(names = "succ")
public abstract static class SuccNode extends CoreMethodNode {

public SuccNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SuccNode(SuccNode prev) {
super(prev);
}

@Specialization
public RubyString succ(RubyString string) {
notDesignedForCompilation();

if (string.length() > 0) {
return getContext().makeString(StringSupport.succCommon(string.getBytes()));
} else {
return getContext().makeString("");
}
}
}

@CoreMethod(names = "succ!")
public abstract static class SuccBangNode extends CoreMethodNode {

public SuccBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SuccBangNode(SuccBangNode prev) {
super(prev);
}

@Specialization
public RubyString succBang(RubyString string) {
notDesignedForCompilation();

if (string.isFrozen()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(getContext().getCoreLibrary().frozenError("String", this));
}

if (string.length() > 0) {
string.set(StringSupport.succCommon(string.getBytes()));
}

return string;
}
}

@CoreMethod(names = "sum")
public abstract static class SumNode extends CoreMethodNode {

Expand Down
Expand Up @@ -136,6 +136,12 @@ public long callLongFixnum(
this));
}

/**
* Check if a specific method is defined on the receiver object.
* This check is "static" and should only be used in a few VM operations.
* In many cases, a dynamic call to Ruby's respond_to? should be used instead.
* Similar to MRI rb_check_funcall().
*/
public boolean doesRespondTo(
VirtualFrame frame,
Object methodName,
Expand Down

0 comments on commit b4c11c6

Please sign in to comment.