Skip to content

Commit

Permalink
Showing 9 changed files with 125 additions and 85 deletions.
9 changes: 6 additions & 3 deletions ci.hocon
Original file line number Diff line number Diff line change
@@ -121,16 +121,19 @@ jruby-truffle: {
}

gate-caps: {
capabilities: [linux, amd64, gate, post-push]
capabilities: [linux, amd64]
target: [gate, post-push]
}

bench-caps: {
capabilities: [x52, linux, amd64, bench, post-push]
capabilities: [x52, linux, amd64]
target: [bench, post-push]
timelimit: "02:00:00"
}

daily-bench-caps: {
capabilities: [x52, linux, amd64, daily]
capabilities: [x52, linux]
target: [daily]
timelimit: "02:00:00"
}

32 changes: 32 additions & 0 deletions spec/truffle/specs/truffle/string/truncate_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright (c) 2016 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:
#
# Eclipse Public License version 1.0
# GNU General Public License version 2
# GNU Lesser General Public License version 2.1
# OTHER DEALINGS IN THE SOFTWARE.

require_relative '../../../../ruby/spec_helper'

describe "Truffle::String.truncate" do
it "should truncate if the new byte length is shorter than the current length" do
str = "abcdef"

Truffle::String.truncate(str, 3)

str.should == "abc"
end

it "should raise an error if the new byte length is greater than the current length" do
lambda do
Truffle::String.truncate("abc", 10)
end.should raise_error(ArgumentError)
end

it "should raise an error if the new byte length is negative" do
lambda do
Truffle::String.truncate("abc", -1)
end.should raise_error(ArgumentError)
end
end
9 changes: 3 additions & 6 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -13,8 +13,6 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleOptions;
import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.java.JavaInterop;
import com.oracle.truffle.api.object.DynamicObject;
@@ -33,9 +31,7 @@
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreMethodNodeManager;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveManager;
import org.jruby.truffle.builtins.PrimitiveNodeConstructor;
import org.jruby.truffle.core.array.ArrayNodes;
import org.jruby.truffle.core.array.ArrayNodesFactory;
import org.jruby.truffle.core.array.TruffleArrayNodesFactory;
@@ -87,6 +83,7 @@
import org.jruby.truffle.core.rubinius.WeakRefPrimitiveNodesFactory;
import org.jruby.truffle.core.string.StringNodesFactory;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.core.string.TruffleStringNodesFactory;
import org.jruby.truffle.core.symbol.SymbolNodesFactory;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationLayoutImpl;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationNodesFactory;
@@ -133,10 +130,8 @@
import org.jruby.util.cli.OutputStrings;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
@@ -615,6 +610,7 @@ public CoreLibrary(RubyContext context) {
defineModule(truffleModule, "Ropes");
defineModule(truffleModule, "GC");
defineModule(truffleModule, "Array");
defineModule(truffleModule, "String");
final DynamicObject attachments = defineModule(truffleModule, "Attachments");
defineModule(attachments, "Internal");
defineModule(truffleModule, "Boot");
@@ -846,6 +842,7 @@ public void addCoreMethods() {
coreMethodNodeManager.addCoreMethodNodes(TruffleDebugNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(TruffleBindingNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(TruffleArrayNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(TruffleStringNodesFactory.getFactories());
coreMethodNodeManager.addCoreMethodNodes(BCryptNodesFactory.getFactories());
return null;
}));
Original file line number Diff line number Diff line change
@@ -89,7 +89,6 @@
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.CoreMethodNode;
import org.jruby.truffle.builtins.NonStandard;
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.builtins.PrimitiveNode;
@@ -245,8 +244,6 @@ protected boolean isUTF8AndUSASCII(DynamicObject string, DynamicObject other) {
public abstract static class MulNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;
@Child private RopeNodes.MakeConcatNode makeConcatNode;
@Child private RopeNodes.MakeLeafRopeNode makeLeafRopeNode;
@Child private ToIntNode toIntNode;

public MulNode(RubyContext context, SourceSection sourceSection) {
@@ -286,12 +283,6 @@ public DynamicObject multiply(VirtualFrame frame, DynamicObject string, Object t
return executeInt(frame, string, toIntNode.doInt(frame, times));
}

protected static boolean isSingleByteString(DynamicObject string) {
assert RubyGuards.isRubyString(string);

return rope(string).byteLength() == 1;
}

}

@CoreMethod(names = {"==", "===", "eql?"}, required = 1)
@@ -1490,38 +1481,6 @@ public Object lstripBang(DynamicObject string) {
}
}

@NonStandard
@CoreMethod(names = "num_bytes=", lowerFixnumParameters = 0, required = 1)
public abstract static class SetNumBytesNode extends CoreMethodArrayArgumentsNode {

@Child private RopeNodes.MakeSubstringNode makeSubstringNode;

public SetNumBytesNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
makeSubstringNode = RopeNodesFactory.MakeSubstringNodeGen.create(null, null, null);
}

@Specialization
public DynamicObject setNumBytes(DynamicObject string, int count,
@Cached("create()") BranchProfile errorProfile) {
final Rope rope = rope(string);

if (count > rope.byteLength()) {
errorProfile.enter();
throw new RaiseException(coreExceptions().argumentError(formatError(count, rope), this));
}

StringOperations.setRope(string, makeSubstringNode.executeMake(rope, 0, count));

return string;
}

@TruffleBoundary
private String formatError(int count, final Rope rope) {
return String.format("Invalid byte count: %d exceeds string size of %d bytes", count, rope.byteLength());
}
}

@CoreMethod(names = "ord")
@ImportStatic(StringGuards.class)
public abstract static class OrdNode extends CoreMethodArrayArgumentsNode {
@@ -2848,26 +2807,6 @@ public Object stringByteSubstring(DynamicObject string, DynamicObject range, Not

}

@Primitive(name = "string_check_null_safe", needsSelf = false)
public static abstract class StringCheckNullSafePrimitiveNode extends PrimitiveArrayArgumentsNode {

@Specialization
public DynamicObject stringCheckNullSafe(DynamicObject string,
@Cached("create()") BranchProfile errorProfile) {
final byte[] bytes = rope(string).getBytes();

for (int i = 0; i < bytes.length; i++) {
if (bytes[i] == 0) {
errorProfile.enter();
throw new RaiseException(coreExceptions().argumentError("string contains NULL byte", this));
}
}

return string;
}

}

@Primitive(name = "string_chr_at", lowerFixnumParameters = 0)
@ImportStatic(StringGuards.class)
public static abstract class StringChrAtPrimitiveNode extends PrimitiveArrayArgumentsNode {
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2016 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:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.string;


import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.control.RaiseException;

import static org.jruby.truffle.core.string.StringOperations.rope;

@CoreClass("Truffle::String")
public class TruffleStringNodes {

@CoreMethod(names = "truncate", onSingleton = true, required = 2, lowerFixnumParameters = 1)
public abstract static class TruncateNode extends CoreMethodArrayArgumentsNode {

@Specialization(guards = { "newByteLength < 0" })
@TruffleBoundary
public DynamicObject truncateLengthNegative(DynamicObject string, int newByteLength) {
throw new RaiseException(
getContext().getCoreExceptions().argumentError(formatNegativeError(newByteLength), this));
}

@Specialization(guards = { "newByteLength >= 0", "isRubyString(string)", "isNewLengthTooLarge(string, newByteLength)" })
@TruffleBoundary
public DynamicObject truncateLengthTooLong(DynamicObject string, int newByteLength) {
throw new RaiseException(
getContext().getCoreExceptions().argumentError(formatTooLongError(newByteLength, rope(string)), this));
}

@Specialization(guards = { "newByteLength >= 0", "isRubyString(string)", "!isNewLengthTooLarge(string, newByteLength)" })
public DynamicObject stealStorage(DynamicObject string, int newByteLength,
@Cached("createX()") RopeNodes.MakeSubstringNode makeSubstringNode) {

StringOperations.setRope(string, makeSubstringNode.executeMake(rope(string), 0, newByteLength));

return string;
}

protected static boolean isNewLengthTooLarge(DynamicObject string, int newByteLength) {
assert RubyGuards.isRubyString(string);

return newByteLength > rope(string).byteLength();
}

@TruffleBoundary
private String formatNegativeError(int count) {
return String.format("Invalid byte count: %d is negative", count);
}

@TruffleBoundary
private String formatTooLongError(int count, final Rope rope) {
return String.format("Invalid byte count: %d exceeds string size of %d bytes", count, rope.byteLength());
}

}

}
Original file line number Diff line number Diff line change
@@ -62,9 +62,4 @@ public DispatchAction getDispatchAction() {
return dispatchAction;
}

public void forceUncached() {
adoptChildren();
first.replace(new UncachedDispatchNode(context, ignoreVisibility, dispatchAction, missingBehavior));
}

}
Original file line number Diff line number Diff line change
@@ -67,6 +67,7 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam
this.methodName = methodName;
this.receiver = receiver;
this.arguments = arguments;

if (block == null) {
this.block = null;
} else {
@@ -76,8 +77,6 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam
this.isSplatted = isSplatted;
this.isVCall = isVCall;
this.ignoreVisibility = ignoreVisibility;

this.dispatchHead = DispatchHeadNodeFactory.createMethodCall(context, ignoreVisibility);
}

@Override
@@ -86,6 +85,11 @@ public Object execute(VirtualFrame frame) {
final Object[] argumentsObjects = executeArguments(frame);
final DynamicObject blockObject = executeBlock(frame);

if (dispatchHead == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
dispatchHead = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), ignoreVisibility));
}

return dispatchHead.call(frame, receiverObject, methodName, blockObject, argumentsObjects);
}

10 changes: 3 additions & 7 deletions truffle/src/main/ruby/core/string.rb
Original file line number Diff line number Diff line change
@@ -112,10 +112,6 @@ def find_character(offset)
raise PrimitiveFailure, "String#find_character primitive failed"
end

def num_bytes
bytesize
end

def byte_append(str)
Truffle.primitive :string_byte_append
raise TypeError, "String#byte_append primitive only accepts Strings"
@@ -436,7 +432,7 @@ def suffix?(other)

def shorten!(size)
return if bytesize == 0
self.num_bytes -= size
Truffle::String.truncate(self, bytesize - size)
end

def each_codepoint
@@ -937,7 +933,7 @@ def chop!
end
end

self.num_bytes = bytes
Truffle::String.truncate(self, bytes)

self
end
@@ -1003,7 +999,7 @@ def chomp!(sep=undefined)
bytes = bytesize - size
end

self.num_bytes = bytes
Truffle::String.truncate(self, bytes)

self
end
2 changes: 1 addition & 1 deletion truffle/src/main/ruby/core/symbol.rb
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@ def [](index, other = undefined)
end

str = to_s
match_data = index.search_region(str, 0, str.num_bytes, true)
match_data = index.search_region(str, 0, str.bytesize, true)
Regexp.last_match = match_data
if match_data
result = match_data.to_s

0 comments on commit 3e45a8e

Please sign in to comment.